1e97ad33aSDoug Rabson /* 2e97ad33aSDoug Rabson * Copyright (c) 2017-2020 Juniper Networks, Inc. 3e97ad33aSDoug Rabson * All rights reserved. 4e97ad33aSDoug Rabson * 5e97ad33aSDoug Rabson * Redistribution and use in source and binary forms, with or without 6e97ad33aSDoug Rabson * modification, are permitted provided that the following conditions 7e97ad33aSDoug Rabson * are met: 8e97ad33aSDoug Rabson * 1. Redistributions of source code must retain the above copyright 9e97ad33aSDoug Rabson * notice, this list of conditions and the following disclaimer. 10e97ad33aSDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 11e97ad33aSDoug Rabson * notice, this list of conditions and the following disclaimer in the 12e97ad33aSDoug Rabson * documentation and/or other materials provided with the distribution. 13e97ad33aSDoug Rabson * 14e97ad33aSDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15e97ad33aSDoug Rabson * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16e97ad33aSDoug Rabson * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17e97ad33aSDoug Rabson * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18e97ad33aSDoug Rabson * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19e97ad33aSDoug Rabson * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20e97ad33aSDoug Rabson * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21e97ad33aSDoug Rabson * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22e97ad33aSDoug Rabson * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23e97ad33aSDoug Rabson * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24e97ad33aSDoug Rabson * 25e97ad33aSDoug Rabson */ 26e97ad33aSDoug Rabson 27e97ad33aSDoug Rabson /* This file contains VFS file ops for the 9P protocol. 28e97ad33aSDoug Rabson * This makes the upper layer of the p9fs driver. These functions interact 29e97ad33aSDoug Rabson * with the VFS layer and lower layer of p9fs driver which is 9Pnet. All 30e97ad33aSDoug Rabson * the user file operations are handled here. 31e97ad33aSDoug Rabson */ 32e97ad33aSDoug Rabson #include <sys/cdefs.h> 33e97ad33aSDoug Rabson #include <sys/systm.h> 34e97ad33aSDoug Rabson #include <sys/bio.h> 35e97ad33aSDoug Rabson #include <sys/buf.h> 36e97ad33aSDoug Rabson #include <sys/dirent.h> 37e97ad33aSDoug Rabson #include <sys/fcntl.h> 38e97ad33aSDoug Rabson #include <sys/namei.h> 39e97ad33aSDoug Rabson #include <sys/priv.h> 40e97ad33aSDoug Rabson #include <sys/stat.h> 41e97ad33aSDoug Rabson #include <sys/vnode.h> 42daa2c99cSVal Packett #include <sys/rwlock.h> 43daa2c99cSVal Packett #include <sys/vmmeter.h> 44e97ad33aSDoug Rabson 45e97ad33aSDoug Rabson #include <vm/vm.h> 46e97ad33aSDoug Rabson #include <vm/vm_extern.h> 47e97ad33aSDoug Rabson #include <vm/vm_object.h> 48daa2c99cSVal Packett #include <vm/vm_page.h> 49daa2c99cSVal Packett #include <vm/vm_pager.h> 50e97ad33aSDoug Rabson #include <vm/vnode_pager.h> 51e97ad33aSDoug Rabson 52e97ad33aSDoug Rabson #include <fs/p9fs/p9_client.h> 53e97ad33aSDoug Rabson #include <fs/p9fs/p9_debug.h> 54e97ad33aSDoug Rabson #include <fs/p9fs/p9fs.h> 55e97ad33aSDoug Rabson #include <fs/p9fs/p9fs_proto.h> 56e97ad33aSDoug Rabson 57e97ad33aSDoug Rabson /* File permissions. */ 58e97ad33aSDoug Rabson #define IEXEC 0000100 /* Executable. */ 59e97ad33aSDoug Rabson #define IWRITE 0000200 /* Writeable. */ 60e97ad33aSDoug Rabson #define IREAD 0000400 /* Readable. */ 61e97ad33aSDoug Rabson #define ISVTX 0001000 /* Sticky bit. */ 62e97ad33aSDoug Rabson #define ISGID 0002000 /* Set-gid. */ 63e97ad33aSDoug Rabson #define ISUID 0004000 /* Set-uid. */ 64e97ad33aSDoug Rabson 65e97ad33aSDoug Rabson static MALLOC_DEFINE(M_P9UIOV, "uio", "UIOV structures for strategy in p9fs"); 66e97ad33aSDoug Rabson extern uma_zone_t p9fs_io_buffer_zone; 67e97ad33aSDoug Rabson extern uma_zone_t p9fs_getattr_zone; 68e97ad33aSDoug Rabson extern uma_zone_t p9fs_setattr_zone; 69daa2c99cSVal Packett extern uma_zone_t p9fs_pbuf_zone; 70e97ad33aSDoug Rabson /* For the root vnode's vnops. */ 71e97ad33aSDoug Rabson struct vop_vector p9fs_vnops; 72e97ad33aSDoug Rabson 73e97ad33aSDoug Rabson static uint32_t p9fs_unix2p9_mode(uint32_t mode); 74e97ad33aSDoug Rabson 75e97ad33aSDoug Rabson static void 76e97ad33aSDoug Rabson p9fs_itimes(struct vnode *vp) 77e97ad33aSDoug Rabson { 78e97ad33aSDoug Rabson struct p9fs_node *node; 79e97ad33aSDoug Rabson struct timespec ts; 80e97ad33aSDoug Rabson struct p9fs_inode *inode; 81e97ad33aSDoug Rabson 82e97ad33aSDoug Rabson node = P9FS_VTON(vp); 83e97ad33aSDoug Rabson inode = &node->inode; 84e97ad33aSDoug Rabson 85e97ad33aSDoug Rabson vfs_timestamp(&ts); 86e97ad33aSDoug Rabson inode->i_mtime = ts.tv_sec; 87e97ad33aSDoug Rabson } 88e97ad33aSDoug Rabson 89e97ad33aSDoug Rabson /* 90e97ad33aSDoug Rabson * Cleanup the p9fs node, the in memory representation of a vnode for p9fs. 91e97ad33aSDoug Rabson * The cleanup includes invalidating all cache entries for the vnode, 92e97ad33aSDoug Rabson * destroying the vobject, removing vnode from hashlist, removing p9fs node 93e97ad33aSDoug Rabson * from the list of session p9fs nodes, and disposing of the p9fs node. 94e97ad33aSDoug Rabson * Basically it is doing a reverse of what a create/vget does. 95e97ad33aSDoug Rabson */ 96e97ad33aSDoug Rabson void 97e97ad33aSDoug Rabson p9fs_cleanup(struct p9fs_node *np) 98e97ad33aSDoug Rabson { 99e97ad33aSDoug Rabson struct vnode *vp; 100e97ad33aSDoug Rabson struct p9fs_session *vses; 101e97ad33aSDoug Rabson 102e97ad33aSDoug Rabson if (np == NULL) 103e97ad33aSDoug Rabson return; 104e97ad33aSDoug Rabson 105e97ad33aSDoug Rabson vp = P9FS_NTOV(np); 106e97ad33aSDoug Rabson vses = np->p9fs_ses; 107e97ad33aSDoug Rabson 108e97ad33aSDoug Rabson /* Remove the vnode from hash list if vnode is not already deleted */ 109e97ad33aSDoug Rabson if ((np->flags & P9FS_NODE_DELETED) == 0) 110e97ad33aSDoug Rabson vfs_hash_remove(vp); 111e97ad33aSDoug Rabson 112e97ad33aSDoug Rabson P9FS_LOCK(vses); 113e97ad33aSDoug Rabson if ((np->flags & P9FS_NODE_IN_SESSION) != 0) { 114e97ad33aSDoug Rabson np->flags &= ~P9FS_NODE_IN_SESSION; 115e97ad33aSDoug Rabson STAILQ_REMOVE(&vses->virt_node_list, np, p9fs_node, p9fs_node_next); 116e97ad33aSDoug Rabson } else { 117e97ad33aSDoug Rabson P9FS_UNLOCK(vses); 118e97ad33aSDoug Rabson return; 119e97ad33aSDoug Rabson } 120e97ad33aSDoug Rabson P9FS_UNLOCK(vses); 121e97ad33aSDoug Rabson 122e97ad33aSDoug Rabson /* Invalidate all entries to a particular vnode. */ 123e97ad33aSDoug Rabson cache_purge(vp); 124e97ad33aSDoug Rabson 125e97ad33aSDoug Rabson /* Destroy the vm object and flush associated pages. */ 126e97ad33aSDoug Rabson vnode_destroy_vobject(vp); 127e97ad33aSDoug Rabson 128e97ad33aSDoug Rabson /* Remove all the FID */ 129e97ad33aSDoug Rabson p9fs_fid_remove_all(np, FALSE); 130e97ad33aSDoug Rabson 131e97ad33aSDoug Rabson /* Dispose all node knowledge.*/ 132e97ad33aSDoug Rabson p9fs_destroy_node(&np); 133e97ad33aSDoug Rabson } 134e97ad33aSDoug Rabson 135e97ad33aSDoug Rabson /* 136e97ad33aSDoug Rabson * Reclaim VOP is defined to be called for every vnode. This starts off 137e97ad33aSDoug Rabson * the cleanup by clunking(remove the fid on the server) and calls 138e97ad33aSDoug Rabson * p9fs_cleanup to free all the resources allocated for p9fs node. 139e97ad33aSDoug Rabson */ 140e97ad33aSDoug Rabson static int 141e97ad33aSDoug Rabson p9fs_reclaim(struct vop_reclaim_args *ap) 142e97ad33aSDoug Rabson { 143e97ad33aSDoug Rabson struct vnode *vp; 144e97ad33aSDoug Rabson struct p9fs_node *np; 145e97ad33aSDoug Rabson 146e97ad33aSDoug Rabson vp = ap->a_vp; 147e97ad33aSDoug Rabson np = P9FS_VTON(vp); 148e97ad33aSDoug Rabson 149e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: vp:%p node:%p\n", __func__, vp, np); 150e97ad33aSDoug Rabson p9fs_cleanup(np); 151e97ad33aSDoug Rabson 152e97ad33aSDoug Rabson return (0); 153e97ad33aSDoug Rabson } 154e97ad33aSDoug Rabson 155e97ad33aSDoug Rabson /* 156e97ad33aSDoug Rabson * recycle vnodes which are no longer referenced i.e, their usecount is zero 157e97ad33aSDoug Rabson */ 158e97ad33aSDoug Rabson static int 159e97ad33aSDoug Rabson p9fs_inactive(struct vop_inactive_args *ap) 160e97ad33aSDoug Rabson { 161e97ad33aSDoug Rabson struct vnode *vp; 162e97ad33aSDoug Rabson struct p9fs_node *np; 163e97ad33aSDoug Rabson 164e97ad33aSDoug Rabson vp = ap->a_vp; 165e97ad33aSDoug Rabson np = P9FS_VTON(vp); 166e97ad33aSDoug Rabson 167e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: vp:%p node:%p file:%s\n", __func__, vp, np, np->inode.i_name); 168e97ad33aSDoug Rabson if (np->flags & P9FS_NODE_DELETED) 169e97ad33aSDoug Rabson vrecycle(vp); 170e97ad33aSDoug Rabson 171e97ad33aSDoug Rabson return (0); 172e97ad33aSDoug Rabson } 173e97ad33aSDoug Rabson 174e97ad33aSDoug Rabson struct p9fs_lookup_alloc_arg { 175e97ad33aSDoug Rabson struct componentname *cnp; 176e97ad33aSDoug Rabson struct p9fs_node *dnp; 177e97ad33aSDoug Rabson struct p9_fid *newfid; 178e97ad33aSDoug Rabson }; 179e97ad33aSDoug Rabson 180e97ad33aSDoug Rabson /* Callback for vn_get_ino */ 181e97ad33aSDoug Rabson static int 182e97ad33aSDoug Rabson p9fs_lookup_alloc(struct mount *mp, void *arg, int lkflags, struct vnode **vpp) 183e97ad33aSDoug Rabson { 184e97ad33aSDoug Rabson struct p9fs_lookup_alloc_arg *p9aa = arg; 185e97ad33aSDoug Rabson 186e97ad33aSDoug Rabson return (p9fs_vget_common(mp, NULL, p9aa->cnp->cn_lkflags, p9aa->dnp, 187e97ad33aSDoug Rabson p9aa->newfid, vpp, p9aa->cnp->cn_nameptr)); 188e97ad33aSDoug Rabson } 189e97ad33aSDoug Rabson 190e97ad33aSDoug Rabson /* 191e97ad33aSDoug Rabson * p9fs_lookup is called for every component name that is being searched for. 192e97ad33aSDoug Rabson * 193e97ad33aSDoug Rabson * I. If component is found on the server, we look for the in-memory 194e97ad33aSDoug Rabson * repesentation(vnode) of this component in namecache. 195e97ad33aSDoug Rabson * A. If the node is found in the namecache, we check is the vnode is still 196e97ad33aSDoug Rabson * valid. 197e97ad33aSDoug Rabson * 1. If it is still valid, return vnode. 198e97ad33aSDoug Rabson * 2. If it is not valid, we remove this vnode from the name cache and 199e97ad33aSDoug Rabson * create a new vnode for the component and return that vnode. 200e97ad33aSDoug Rabson * B. If the vnode is not found in the namecache, we look for it in the 201e97ad33aSDoug Rabson * hash list. 202e97ad33aSDoug Rabson * 1. If the vnode is in the hash list, we check if the vnode is still 203e97ad33aSDoug Rabson * valid. 204e97ad33aSDoug Rabson * a. If it is still valid, we add that vnode to the namecache for 205e97ad33aSDoug Rabson * future lookups and return the vnode. 206e97ad33aSDoug Rabson * b. If it is not valid, create a new vnode and p9fs node, 207e97ad33aSDoug Rabson * initialize them and return the vnode. 208e97ad33aSDoug Rabson * 2. If the vnode is not found in the hash list, we create a new vnode 209e97ad33aSDoug Rabson * and p9fs node, initialize them and return the vnode. 210e97ad33aSDoug Rabson * II. If the component is not found on the server, an error code is returned. 211e97ad33aSDoug Rabson * A. For the creation case, we return EJUSTRETURN so VFS can handle it. 212e97ad33aSDoug Rabson * B. For all other cases, ENOENT is returned. 213e97ad33aSDoug Rabson */ 214e97ad33aSDoug Rabson static int 215e97ad33aSDoug Rabson p9fs_lookup(struct vop_lookup_args *ap) 216e97ad33aSDoug Rabson { 217e97ad33aSDoug Rabson struct vnode *dvp; 218e97ad33aSDoug Rabson struct vnode **vpp, *vp; 219e97ad33aSDoug Rabson struct componentname *cnp; 220e97ad33aSDoug Rabson struct p9fs_node *dnp; /*dir p9_node */ 221e97ad33aSDoug Rabson struct p9fs_node *np; 222e97ad33aSDoug Rabson struct p9fs_session *vses; 223e97ad33aSDoug Rabson struct mount *mp; /* Get the mount point */ 224e97ad33aSDoug Rabson struct p9_fid *dvfid, *newfid; 225e97ad33aSDoug Rabson int error; 226e97ad33aSDoug Rabson struct vattr vattr; 227e97ad33aSDoug Rabson int flags; 228e97ad33aSDoug Rabson char tmpchr; 229e97ad33aSDoug Rabson 230e97ad33aSDoug Rabson dvp = ap->a_dvp; 231e97ad33aSDoug Rabson vpp = ap->a_vpp; 232e97ad33aSDoug Rabson cnp = ap->a_cnp; 233e97ad33aSDoug Rabson dnp = P9FS_VTON(dvp); 234e97ad33aSDoug Rabson error = 0; 235e97ad33aSDoug Rabson flags = cnp->cn_flags; 236e97ad33aSDoug Rabson *vpp = NULLVP; 237e97ad33aSDoug Rabson 238e97ad33aSDoug Rabson if (dnp == NULL) 239e97ad33aSDoug Rabson return (ENOENT); 240e97ad33aSDoug Rabson 24162bb18abSBakul Shah if (cnp->cn_nameptr[0] == '.' && cnp->cn_namelen == 1) { 24256e46225SDoug Rabson vref(dvp); 24356e46225SDoug Rabson *vpp = dvp; 24456e46225SDoug Rabson return (0); 24556e46225SDoug Rabson } 24656e46225SDoug Rabson 247e97ad33aSDoug Rabson vses = dnp->p9fs_ses; 248e97ad33aSDoug Rabson mp = vses->p9fs_mount; 249e97ad33aSDoug Rabson 250e97ad33aSDoug Rabson /* Do the cache part ourselves */ 251e97ad33aSDoug Rabson if ((flags & ISLASTCN) && (mp->mnt_flag & MNT_RDONLY) && 252e97ad33aSDoug Rabson (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) 253e97ad33aSDoug Rabson return (EROFS); 254e97ad33aSDoug Rabson 255e97ad33aSDoug Rabson if (dvp->v_type != VDIR) 256e97ad33aSDoug Rabson return (ENOTDIR); 257e97ad33aSDoug Rabson 258e97ad33aSDoug Rabson error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, curthread); 259e97ad33aSDoug Rabson if (error) 260e97ad33aSDoug Rabson return (error); 261e97ad33aSDoug Rabson 262e97ad33aSDoug Rabson /* Do the directory walk on host to check if file exist */ 263e97ad33aSDoug Rabson dvfid = p9fs_get_fid(vses->clnt, dnp, cnp->cn_cred, VFID, -1, &error); 264e97ad33aSDoug Rabson if (error) 265e97ad33aSDoug Rabson return (error); 266e97ad33aSDoug Rabson 267e97ad33aSDoug Rabson /* 268e97ad33aSDoug Rabson * Save the character present at namelen in nameptr string and 269e97ad33aSDoug Rabson * null terminate the character to get the search name for p9_dir_walk 270e97ad33aSDoug Rabson * This is done to handle when lookup is for "a" and component 271e97ad33aSDoug Rabson * name contains a/b/c 272e97ad33aSDoug Rabson */ 273e97ad33aSDoug Rabson tmpchr = cnp->cn_nameptr[cnp->cn_namelen]; 274e97ad33aSDoug Rabson cnp->cn_nameptr[cnp->cn_namelen] = '\0'; 275e97ad33aSDoug Rabson 276e97ad33aSDoug Rabson /* 277e97ad33aSDoug Rabson * If the client_walk fails, it means the file looking for doesnt exist. 278e97ad33aSDoug Rabson * Create the file is the flags are set or just return the error 279e97ad33aSDoug Rabson */ 280e97ad33aSDoug Rabson newfid = p9_client_walk(dvfid, 1, &cnp->cn_nameptr, 1, &error); 281e97ad33aSDoug Rabson 282e97ad33aSDoug Rabson cnp->cn_nameptr[cnp->cn_namelen] = tmpchr; 283e97ad33aSDoug Rabson 284e97ad33aSDoug Rabson if (error != 0 || newfid == NULL) { 285e97ad33aSDoug Rabson /* Clunk the newfid if it is not NULL */ 286e97ad33aSDoug Rabson if (newfid != NULL) 287e97ad33aSDoug Rabson p9_client_clunk(newfid); 288e97ad33aSDoug Rabson 289e97ad33aSDoug Rabson if (error != ENOENT) 290e97ad33aSDoug Rabson return (error); 291e97ad33aSDoug Rabson 292e97ad33aSDoug Rabson /* The requested file was not found. */ 293e97ad33aSDoug Rabson if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) && 294e97ad33aSDoug Rabson (flags & ISLASTCN)) { 295e97ad33aSDoug Rabson 296e97ad33aSDoug Rabson if (mp->mnt_flag & MNT_RDONLY) 297e97ad33aSDoug Rabson return (EROFS); 298e97ad33aSDoug Rabson 299e97ad33aSDoug Rabson error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, 300e97ad33aSDoug Rabson curthread); 301e97ad33aSDoug Rabson if (!error) { 302e97ad33aSDoug Rabson return (EJUSTRETURN); 303e97ad33aSDoug Rabson } 304e97ad33aSDoug Rabson } 305e97ad33aSDoug Rabson return (error); 306e97ad33aSDoug Rabson } 307e97ad33aSDoug Rabson 308e97ad33aSDoug Rabson /* Look for the entry in the component cache*/ 309e97ad33aSDoug Rabson error = cache_lookup(dvp, vpp, cnp, NULL, NULL); 310e97ad33aSDoug Rabson if (error > 0 && error != ENOENT) { 311e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: Cache lookup error %d \n", __func__, error); 312e97ad33aSDoug Rabson goto out; 313e97ad33aSDoug Rabson } 314e97ad33aSDoug Rabson 315e97ad33aSDoug Rabson if (error == -1) { 316e97ad33aSDoug Rabson vp = *vpp; 317e97ad33aSDoug Rabson /* Check if the entry in cache is stale or not */ 318e97ad33aSDoug Rabson if ((p9fs_node_cmp(vp, &newfid->qid) == 0) && 319e97ad33aSDoug Rabson ((error = VOP_GETATTR(vp, &vattr, cnp->cn_cred)) == 0)) { 320e97ad33aSDoug Rabson goto out; 321e97ad33aSDoug Rabson } 322e97ad33aSDoug Rabson /* 323e97ad33aSDoug Rabson * This case, we have an error coming from getattr, 324e97ad33aSDoug Rabson * act accordingly. 325e97ad33aSDoug Rabson */ 326e97ad33aSDoug Rabson cache_purge(vp); 327e97ad33aSDoug Rabson if (dvp != vp) 328e97ad33aSDoug Rabson vput(vp); 329e97ad33aSDoug Rabson else 330e97ad33aSDoug Rabson vrele(vp); 331e97ad33aSDoug Rabson 332e97ad33aSDoug Rabson *vpp = NULLVP; 333e97ad33aSDoug Rabson } else if (error == ENOENT) { 334e97ad33aSDoug Rabson if (VN_IS_DOOMED(dvp)) 335e97ad33aSDoug Rabson goto out; 336e97ad33aSDoug Rabson if (VOP_GETATTR(dvp, &vattr, cnp->cn_cred) == 0) { 337e97ad33aSDoug Rabson error = ENOENT; 338e97ad33aSDoug Rabson goto out; 339e97ad33aSDoug Rabson } 340e97ad33aSDoug Rabson cache_purge_negative(dvp); 341e97ad33aSDoug Rabson } 342e97ad33aSDoug Rabson /* Reset values */ 343e97ad33aSDoug Rabson error = 0; 344e97ad33aSDoug Rabson vp = NULLVP; 345e97ad33aSDoug Rabson 346e97ad33aSDoug Rabson tmpchr = cnp->cn_nameptr[cnp->cn_namelen]; 347e97ad33aSDoug Rabson cnp->cn_nameptr[cnp->cn_namelen] = '\0'; 348e97ad33aSDoug Rabson 349e97ad33aSDoug Rabson /* 350e97ad33aSDoug Rabson * Looks like we have found an entry. Now take care of all other cases. 351e97ad33aSDoug Rabson */ 352e97ad33aSDoug Rabson if (flags & ISDOTDOT) { 353e97ad33aSDoug Rabson struct p9fs_lookup_alloc_arg p9aa; 354e97ad33aSDoug Rabson p9aa.cnp = cnp; 355e97ad33aSDoug Rabson p9aa.dnp = dnp; 356e97ad33aSDoug Rabson p9aa.newfid = newfid; 357e97ad33aSDoug Rabson error = vn_vget_ino_gen(dvp, p9fs_lookup_alloc, &p9aa, 0, &vp); 358e97ad33aSDoug Rabson if (error) 359e97ad33aSDoug Rabson goto out; 360e97ad33aSDoug Rabson *vpp = vp; 361e97ad33aSDoug Rabson } else { 362e97ad33aSDoug Rabson /* 363e97ad33aSDoug Rabson * client_walk is equivalent to searching a component name in a 364e97ad33aSDoug Rabson * directory(fid) here. If new fid is returned, we have found an 365e97ad33aSDoug Rabson * entry for this component name so, go and create the rest of 366e97ad33aSDoug Rabson * the vnode infra(vget_common) for the returned newfid. 367e97ad33aSDoug Rabson */ 368e97ad33aSDoug Rabson if ((cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) 369e97ad33aSDoug Rabson && (flags & ISLASTCN)) { 370e97ad33aSDoug Rabson error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, 371e97ad33aSDoug Rabson curthread); 372e97ad33aSDoug Rabson if (error) 373e97ad33aSDoug Rabson goto out; 374e97ad33aSDoug Rabson 375e97ad33aSDoug Rabson error = p9fs_vget_common(mp, NULL, cnp->cn_lkflags, 376e97ad33aSDoug Rabson dnp, newfid, &vp, cnp->cn_nameptr); 377e97ad33aSDoug Rabson if (error) 378e97ad33aSDoug Rabson goto out; 379e97ad33aSDoug Rabson 380e97ad33aSDoug Rabson *vpp = vp; 381e97ad33aSDoug Rabson np = P9FS_VTON(vp); 382e97ad33aSDoug Rabson if ((dnp->inode.i_mode & ISVTX) && 383e97ad33aSDoug Rabson cnp->cn_cred->cr_uid != 0 && 384e97ad33aSDoug Rabson cnp->cn_cred->cr_uid != dnp->inode.n_uid && 385e97ad33aSDoug Rabson cnp->cn_cred->cr_uid != np->inode.n_uid) { 386e97ad33aSDoug Rabson vput(*vpp); 387e97ad33aSDoug Rabson *vpp = NULL; 388e97ad33aSDoug Rabson cnp->cn_nameptr[cnp->cn_namelen] = tmpchr; 389e97ad33aSDoug Rabson return (EPERM); 390e97ad33aSDoug Rabson } 391e97ad33aSDoug Rabson } else { 392e97ad33aSDoug Rabson error = p9fs_vget_common(mp, NULL, cnp->cn_lkflags, 393e97ad33aSDoug Rabson dnp, newfid, &vp, cnp->cn_nameptr); 394e97ad33aSDoug Rabson if (error) 395e97ad33aSDoug Rabson goto out; 396e97ad33aSDoug Rabson *vpp = vp; 397e97ad33aSDoug Rabson } 398e97ad33aSDoug Rabson } 399e97ad33aSDoug Rabson 400e97ad33aSDoug Rabson cnp->cn_nameptr[cnp->cn_namelen] = tmpchr; 401e97ad33aSDoug Rabson 402e97ad33aSDoug Rabson /* Store the result the cache if MAKEENTRY is specified in flags */ 403e97ad33aSDoug Rabson if ((cnp->cn_flags & MAKEENTRY) != 0) 404e97ad33aSDoug Rabson cache_enter(dvp, *vpp, cnp); 405e97ad33aSDoug Rabson return (error); 406e97ad33aSDoug Rabson out: 407e97ad33aSDoug Rabson cnp->cn_nameptr[cnp->cn_namelen] = tmpchr; 408e97ad33aSDoug Rabson p9_client_clunk(newfid); 409e97ad33aSDoug Rabson return (error); 410e97ad33aSDoug Rabson } 411e97ad33aSDoug Rabson 412e97ad33aSDoug Rabson /* 413e97ad33aSDoug Rabson * Common creation function for file/directory with respective flags. We first 414e97ad33aSDoug Rabson * open the parent directory in order to create the file under it. For this, 415e97ad33aSDoug Rabson * as 9P protocol suggests, we need to call client_walk to create the open fid. 416e97ad33aSDoug Rabson * Once we have the open fid, the file_create function creates the direntry with 417e97ad33aSDoug Rabson * the name and perm specified under the parent dir. If this succeeds (an entry 418e97ad33aSDoug Rabson * is created for the new file on the server), we create our metadata for this 419e97ad33aSDoug Rabson * file (vnode, p9fs node calling vget). Once we are done, we clunk the open 420e97ad33aSDoug Rabson * fid of the parent directory. 421e97ad33aSDoug Rabson */ 422e97ad33aSDoug Rabson static int 423e97ad33aSDoug Rabson create_common(struct p9fs_node *dnp, struct componentname *cnp, 424e97ad33aSDoug Rabson char *extension, uint32_t perm, uint8_t mode, struct vnode **vpp) 425e97ad33aSDoug Rabson { 426e97ad33aSDoug Rabson char tmpchr; 427e97ad33aSDoug Rabson struct p9_fid *dvfid, *ofid, *newfid; 428e97ad33aSDoug Rabson struct p9fs_session *vses; 429e97ad33aSDoug Rabson struct mount *mp; 430e97ad33aSDoug Rabson int error; 431e97ad33aSDoug Rabson 432e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: name %s\n", __func__, cnp->cn_nameptr); 433e97ad33aSDoug Rabson 434e97ad33aSDoug Rabson vses = dnp->p9fs_ses; 435e97ad33aSDoug Rabson mp = vses->p9fs_mount; 436e97ad33aSDoug Rabson newfid = NULL; 437e97ad33aSDoug Rabson error = 0; 438e97ad33aSDoug Rabson 439e97ad33aSDoug Rabson dvfid = p9fs_get_fid(vses->clnt, dnp, cnp->cn_cred, VFID, -1, &error); 440e97ad33aSDoug Rabson if (error != 0) 441e97ad33aSDoug Rabson return (error); 442e97ad33aSDoug Rabson 443e97ad33aSDoug Rabson /* Clone the directory fid to create the new file */ 444e97ad33aSDoug Rabson ofid = p9_client_walk(dvfid, 0, NULL, 1, &error); 445e97ad33aSDoug Rabson if (error != 0) 446e97ad33aSDoug Rabson return (error); 447e97ad33aSDoug Rabson 448e97ad33aSDoug Rabson /* 449e97ad33aSDoug Rabson * Save the character present at namelen in nameptr string and 450e97ad33aSDoug Rabson * null terminate the character to get the search name for p9_dir_walk 451e97ad33aSDoug Rabson */ 452e97ad33aSDoug Rabson tmpchr = cnp->cn_nameptr[cnp->cn_namelen]; 453e97ad33aSDoug Rabson cnp->cn_nameptr[cnp->cn_namelen] = '\0'; 454e97ad33aSDoug Rabson 455e97ad33aSDoug Rabson error = p9_client_file_create(ofid, cnp->cn_nameptr, perm, mode, 456e97ad33aSDoug Rabson extension); 457e97ad33aSDoug Rabson if (error != 0) { 458e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: p9_client_fcreate failed %d\n", __func__, error); 459e97ad33aSDoug Rabson goto out; 460e97ad33aSDoug Rabson } 461e97ad33aSDoug Rabson 462e97ad33aSDoug Rabson /* If its not hardlink only then do the walk, else we are done. */ 463e97ad33aSDoug Rabson if (!(perm & P9PROTO_DMLINK)) { 464e97ad33aSDoug Rabson /* 465e97ad33aSDoug Rabson * Do the lookup part and add the vnode, p9fs node. Note that vpp 466e97ad33aSDoug Rabson * is filled in here. 467e97ad33aSDoug Rabson */ 468e97ad33aSDoug Rabson newfid = p9_client_walk(dvfid, 1, &cnp->cn_nameptr, 1, &error); 469e97ad33aSDoug Rabson if (newfid != NULL) { 470e97ad33aSDoug Rabson error = p9fs_vget_common(mp, NULL, cnp->cn_lkflags, 471e97ad33aSDoug Rabson dnp, newfid, vpp, cnp->cn_nameptr); 472e97ad33aSDoug Rabson if (error != 0) 473e97ad33aSDoug Rabson goto out; 474e97ad33aSDoug Rabson } else { 475e97ad33aSDoug Rabson /* Not found return NOENTRY.*/ 476e97ad33aSDoug Rabson goto out; 477e97ad33aSDoug Rabson } 478e97ad33aSDoug Rabson 479e97ad33aSDoug Rabson if ((cnp->cn_flags & MAKEENTRY) != 0) 480e97ad33aSDoug Rabson cache_enter(P9FS_NTOV(dnp), *vpp, cnp); 481e97ad33aSDoug Rabson } 482e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: created file under vp %p node %p fid %ju\n", 483e97ad33aSDoug Rabson __func__, *vpp, dnp, (uintmax_t)dvfid->fid); 484e97ad33aSDoug Rabson /* Clunk the open ofid. */ 485e97ad33aSDoug Rabson if (ofid != NULL) 486e97ad33aSDoug Rabson (void)p9_client_clunk(ofid); 487e97ad33aSDoug Rabson 488e97ad33aSDoug Rabson cnp->cn_nameptr[cnp->cn_namelen] = tmpchr; 489e97ad33aSDoug Rabson return (0); 490e97ad33aSDoug Rabson out: 491e97ad33aSDoug Rabson if (ofid != NULL) 492e97ad33aSDoug Rabson (void)p9_client_clunk(ofid); 493e97ad33aSDoug Rabson 494e97ad33aSDoug Rabson if (newfid != NULL) 495e97ad33aSDoug Rabson (void)p9_client_clunk(newfid); 496e97ad33aSDoug Rabson 497e97ad33aSDoug Rabson cnp->cn_nameptr[cnp->cn_namelen] = tmpchr; 498e97ad33aSDoug Rabson return (error); 499e97ad33aSDoug Rabson } 500e97ad33aSDoug Rabson 501e97ad33aSDoug Rabson /* 502e97ad33aSDoug Rabson * This is the main file creation VOP. Make the permissions of the new 503e97ad33aSDoug Rabson * file and call the create_common common code to complete the create. 504e97ad33aSDoug Rabson */ 505e97ad33aSDoug Rabson static int 506e97ad33aSDoug Rabson p9fs_create(struct vop_create_args *ap) 507e97ad33aSDoug Rabson { 508e97ad33aSDoug Rabson struct vnode *dvp; 509e97ad33aSDoug Rabson struct vnode **vpp; 510e97ad33aSDoug Rabson struct componentname *cnp; 511e97ad33aSDoug Rabson uint32_t mode; 512e97ad33aSDoug Rabson struct p9fs_node *dnp; 513e97ad33aSDoug Rabson struct p9fs_inode *dinode; 514e97ad33aSDoug Rabson uint32_t perm; 515e97ad33aSDoug Rabson int ret; 516e97ad33aSDoug Rabson 517e97ad33aSDoug Rabson dvp = ap->a_dvp; 518e97ad33aSDoug Rabson vpp = ap->a_vpp; 519e97ad33aSDoug Rabson cnp = ap->a_cnp; 520e97ad33aSDoug Rabson dnp = P9FS_VTON(dvp); 521e97ad33aSDoug Rabson dinode = &dnp->inode; 522e97ad33aSDoug Rabson mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode); 523e97ad33aSDoug Rabson perm = p9fs_unix2p9_mode(mode); 524e97ad33aSDoug Rabson 525e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: dvp %p\n", __func__, dvp); 526e97ad33aSDoug Rabson 527e97ad33aSDoug Rabson ret = create_common(dnp, cnp, NULL, perm, P9PROTO_ORDWR, vpp); 528e97ad33aSDoug Rabson if (ret == 0) { 529e97ad33aSDoug Rabson P9FS_INCR_LINKS(dinode); 530e97ad33aSDoug Rabson } 531e97ad33aSDoug Rabson 532e97ad33aSDoug Rabson return (ret); 533e97ad33aSDoug Rabson } 534e97ad33aSDoug Rabson 535e97ad33aSDoug Rabson /* 536e97ad33aSDoug Rabson * p9fs_mkdir is the main directory creation vop. Make the permissions of the new dir 537e97ad33aSDoug Rabson * and call the create_common common code to complete the create. 538e97ad33aSDoug Rabson */ 539e97ad33aSDoug Rabson static int 540e97ad33aSDoug Rabson p9fs_mkdir(struct vop_mkdir_args *ap) 541e97ad33aSDoug Rabson { 542e97ad33aSDoug Rabson struct vnode *dvp; 543e97ad33aSDoug Rabson struct vnode **vpp; 544e97ad33aSDoug Rabson struct componentname *cnp; 545e97ad33aSDoug Rabson uint32_t mode; 546e97ad33aSDoug Rabson struct p9fs_node *dnp; 547e97ad33aSDoug Rabson struct p9fs_inode *dinode; 548e97ad33aSDoug Rabson uint32_t perm; 549e97ad33aSDoug Rabson int ret; 550e97ad33aSDoug Rabson 551e97ad33aSDoug Rabson dvp = ap->a_dvp; 552e97ad33aSDoug Rabson vpp = ap->a_vpp; 553e97ad33aSDoug Rabson cnp = ap->a_cnp; 554e97ad33aSDoug Rabson dnp = P9FS_VTON(dvp); 555e97ad33aSDoug Rabson dinode = &dnp->inode; 556e97ad33aSDoug Rabson mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode); 557e97ad33aSDoug Rabson perm = p9fs_unix2p9_mode(mode | S_IFDIR); 558e97ad33aSDoug Rabson 559e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: dvp %p\n", __func__, dvp); 560e97ad33aSDoug Rabson 561e97ad33aSDoug Rabson ret = create_common(dnp, cnp, NULL, perm, P9PROTO_ORDWR, vpp); 562e97ad33aSDoug Rabson if (ret == 0) 563e97ad33aSDoug Rabson P9FS_INCR_LINKS(dinode); 564e97ad33aSDoug Rabson 565e97ad33aSDoug Rabson return (ret); 566e97ad33aSDoug Rabson } 567e97ad33aSDoug Rabson 568e97ad33aSDoug Rabson /* 569e97ad33aSDoug Rabson * p9fs_mknod is the main node creation vop. Make the permissions of the new node 570e97ad33aSDoug Rabson * and call the create_common common code to complete the create. 571e97ad33aSDoug Rabson */ 572e97ad33aSDoug Rabson static int 573e97ad33aSDoug Rabson p9fs_mknod(struct vop_mknod_args *ap) 574e97ad33aSDoug Rabson { 575e97ad33aSDoug Rabson struct vnode *dvp; 576e97ad33aSDoug Rabson struct vnode **vpp; 577e97ad33aSDoug Rabson struct componentname *cnp; 578e97ad33aSDoug Rabson uint32_t mode; 579e97ad33aSDoug Rabson struct p9fs_node *dnp; 580e97ad33aSDoug Rabson struct p9fs_inode *dinode; 581e97ad33aSDoug Rabson uint32_t perm; 582e97ad33aSDoug Rabson int ret; 583e97ad33aSDoug Rabson 584e97ad33aSDoug Rabson dvp = ap->a_dvp; 585e97ad33aSDoug Rabson vpp = ap->a_vpp; 586e97ad33aSDoug Rabson cnp = ap->a_cnp; 587e97ad33aSDoug Rabson dnp = P9FS_VTON(dvp); 588e97ad33aSDoug Rabson dinode = &dnp->inode; 589e97ad33aSDoug Rabson mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode); 590e97ad33aSDoug Rabson perm = p9fs_unix2p9_mode(mode); 591e97ad33aSDoug Rabson 592e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: dvp %p\n", __func__, dvp); 593e97ad33aSDoug Rabson 594e97ad33aSDoug Rabson ret = create_common(dnp, cnp, NULL, perm, P9PROTO_OREAD, vpp); 595e97ad33aSDoug Rabson if (ret == 0) { 596e97ad33aSDoug Rabson P9FS_INCR_LINKS(dinode); 597e97ad33aSDoug Rabson } 598e97ad33aSDoug Rabson 599e97ad33aSDoug Rabson return (ret); 600e97ad33aSDoug Rabson } 601e97ad33aSDoug Rabson 602e97ad33aSDoug Rabson /* Convert open mode permissions to P9 */ 603e97ad33aSDoug Rabson static int 604e97ad33aSDoug Rabson p9fs_uflags_mode(int uflags, int extended) 605e97ad33aSDoug Rabson { 606e97ad33aSDoug Rabson uint32_t ret; 607e97ad33aSDoug Rabson 608e97ad33aSDoug Rabson /* Convert first to O flags.*/ 609e97ad33aSDoug Rabson uflags = OFLAGS(uflags); 610e97ad33aSDoug Rabson 611e97ad33aSDoug Rabson switch (uflags & 3) { 612e97ad33aSDoug Rabson 613e97ad33aSDoug Rabson case O_RDONLY: 614e97ad33aSDoug Rabson ret = P9PROTO_OREAD; 615e97ad33aSDoug Rabson break; 616e97ad33aSDoug Rabson 617e97ad33aSDoug Rabson case O_WRONLY: 618e97ad33aSDoug Rabson ret = P9PROTO_OWRITE; 619e97ad33aSDoug Rabson break; 620e97ad33aSDoug Rabson 621e97ad33aSDoug Rabson case O_RDWR: 622e97ad33aSDoug Rabson ret = P9PROTO_ORDWR; 623e97ad33aSDoug Rabson break; 624e97ad33aSDoug Rabson } 625e97ad33aSDoug Rabson 626e97ad33aSDoug Rabson if (extended) { 627e97ad33aSDoug Rabson if (uflags & O_EXCL) 628e97ad33aSDoug Rabson ret |= P9PROTO_OEXCL; 629e97ad33aSDoug Rabson 630e97ad33aSDoug Rabson if (uflags & O_APPEND) 631e97ad33aSDoug Rabson ret |= P9PROTO_OAPPEND; 632e97ad33aSDoug Rabson } 633e97ad33aSDoug Rabson 634e97ad33aSDoug Rabson return (ret); 635e97ad33aSDoug Rabson } 636e97ad33aSDoug Rabson 637e97ad33aSDoug Rabson /* 638e97ad33aSDoug Rabson * This is the main open VOP for every file open. If the file is already 639e97ad33aSDoug Rabson * open, then increment and return. If there is no open fid for this file, 640e97ad33aSDoug Rabson * there needs to be a client_walk which creates a new open fid for this file. 641e97ad33aSDoug Rabson * Once we have a open fid, call the open on this file with the mode creating 642e97ad33aSDoug Rabson * the vobject. 643e97ad33aSDoug Rabson */ 644e97ad33aSDoug Rabson static int 645e97ad33aSDoug Rabson p9fs_open(struct vop_open_args *ap) 646e97ad33aSDoug Rabson { 647e97ad33aSDoug Rabson int error; 648e97ad33aSDoug Rabson struct vnode *vp; 649e97ad33aSDoug Rabson struct p9fs_node *np; 650e97ad33aSDoug Rabson struct p9fs_session *vses; 651e97ad33aSDoug Rabson struct p9_fid *vofid, *vfid; 652e97ad33aSDoug Rabson size_t filesize; 653e97ad33aSDoug Rabson uint32_t mode; 654e97ad33aSDoug Rabson 655e97ad33aSDoug Rabson error = 0; 656e97ad33aSDoug Rabson vp = ap->a_vp; 657e97ad33aSDoug Rabson np = P9FS_VTON(vp); 658e97ad33aSDoug Rabson vses = np->p9fs_ses; 659e97ad33aSDoug Rabson 660e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: vp %p\n", __func__, vp); 661e97ad33aSDoug Rabson 662e97ad33aSDoug Rabson if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) 663e97ad33aSDoug Rabson return (EOPNOTSUPP); 664e97ad33aSDoug Rabson 665e97ad33aSDoug Rabson error = p9fs_reload_stats_dotl(vp, ap->a_cred); 666e97ad33aSDoug Rabson if (error != 0) 667e97ad33aSDoug Rabson return (error); 668e97ad33aSDoug Rabson 669e97ad33aSDoug Rabson ASSERT_VOP_LOCKED(vp, __func__); 670e97ad33aSDoug Rabson /* 671e97ad33aSDoug Rabson * Invalidate the pages of the vm_object cache if the file is modified 672e97ad33aSDoug Rabson * based on the flag set in reload stats 673e97ad33aSDoug Rabson */ 674e97ad33aSDoug Rabson if (vp->v_type == VREG && (np->flags & P9FS_NODE_MODIFIED) != 0) { 675e97ad33aSDoug Rabson error = vinvalbuf(vp, 0, 0, 0); 676e97ad33aSDoug Rabson if (error != 0) 677e97ad33aSDoug Rabson return (error); 678e97ad33aSDoug Rabson np->flags &= ~P9FS_NODE_MODIFIED; 679e97ad33aSDoug Rabson } 680e97ad33aSDoug Rabson 681e97ad33aSDoug Rabson vfid = p9fs_get_fid(vses->clnt, np, ap->a_cred, VFID, -1, &error); 682e97ad33aSDoug Rabson if (error != 0) 683e97ad33aSDoug Rabson return (error); 684e97ad33aSDoug Rabson 685e97ad33aSDoug Rabson /* 686e97ad33aSDoug Rabson * Translate kernel fflags to 9p mode 687e97ad33aSDoug Rabson */ 688e97ad33aSDoug Rabson mode = p9fs_uflags_mode(ap->a_mode, 1); 689e97ad33aSDoug Rabson 690e97ad33aSDoug Rabson /* 691e97ad33aSDoug Rabson * Search the fid in vofid_list for current user. If found increase the open 692e97ad33aSDoug Rabson * count and return. If not found clone a new fid and open the file using 693e97ad33aSDoug Rabson * that cloned fid. 694e97ad33aSDoug Rabson */ 695e97ad33aSDoug Rabson vofid = p9fs_get_fid(vses->clnt, np, ap->a_cred, VOFID, mode, &error); 696e97ad33aSDoug Rabson if (vofid != NULL) { 697e97ad33aSDoug Rabson vofid->v_opens++; 698e97ad33aSDoug Rabson return (0); 699e97ad33aSDoug Rabson } else { 700e97ad33aSDoug Rabson /*vofid is the open fid for this file.*/ 701e97ad33aSDoug Rabson vofid = p9_client_walk(vfid, 0, NULL, 1, &error); 702e97ad33aSDoug Rabson if (error != 0) 703e97ad33aSDoug Rabson return (error); 704e97ad33aSDoug Rabson } 705e97ad33aSDoug Rabson 706e97ad33aSDoug Rabson error = p9_client_open(vofid, mode); 707e97ad33aSDoug Rabson if (error != 0) 708e97ad33aSDoug Rabson p9_client_clunk(vofid); 709e97ad33aSDoug Rabson else { 710e97ad33aSDoug Rabson vofid->v_opens = 1; 711e97ad33aSDoug Rabson filesize = np->inode.i_size; 712e97ad33aSDoug Rabson vnode_create_vobject(vp, filesize, ap->a_td); 713e97ad33aSDoug Rabson p9fs_fid_add(np, vofid, VOFID); 714e97ad33aSDoug Rabson } 715e97ad33aSDoug Rabson 716e97ad33aSDoug Rabson return (error); 717e97ad33aSDoug Rabson } 718e97ad33aSDoug Rabson 719e97ad33aSDoug Rabson /* 720e97ad33aSDoug Rabson * Close the open references. Just reduce the open count on vofid and return. 721e97ad33aSDoug Rabson * Let clunking of VOFID happen in p9fs_reclaim. 722e97ad33aSDoug Rabson */ 723e97ad33aSDoug Rabson static int 724e97ad33aSDoug Rabson p9fs_close(struct vop_close_args *ap) 725e97ad33aSDoug Rabson { 726e97ad33aSDoug Rabson struct vnode *vp; 727e97ad33aSDoug Rabson struct p9fs_node *np; 728e97ad33aSDoug Rabson struct p9fs_session *vses; 729e97ad33aSDoug Rabson struct p9_fid *vofid; 730e97ad33aSDoug Rabson int error; 731e97ad33aSDoug Rabson 732e97ad33aSDoug Rabson vp = ap->a_vp; 733e97ad33aSDoug Rabson np = P9FS_VTON(vp); 734e97ad33aSDoug Rabson 735e97ad33aSDoug Rabson if (np == NULL) 736e97ad33aSDoug Rabson return (0); 737e97ad33aSDoug Rabson 738e97ad33aSDoug Rabson vses = np->p9fs_ses; 739e97ad33aSDoug Rabson error = 0; 740e97ad33aSDoug Rabson 741e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: file_name %s\n", __func__, np->inode.i_name); 742e97ad33aSDoug Rabson 743e97ad33aSDoug Rabson /* 744e97ad33aSDoug Rabson * Translate kernel fflags to 9p mode 745e97ad33aSDoug Rabson */ 746e97ad33aSDoug Rabson vofid = p9fs_get_fid(vses->clnt, np, ap->a_cred, VOFID, 747e97ad33aSDoug Rabson p9fs_uflags_mode(ap->a_fflag, 1), &error); 748e97ad33aSDoug Rabson if (vofid == NULL) 749e97ad33aSDoug Rabson return (0); 750e97ad33aSDoug Rabson 751e97ad33aSDoug Rabson vofid->v_opens--; 752e97ad33aSDoug Rabson 753e97ad33aSDoug Rabson return (0); 754e97ad33aSDoug Rabson } 755e97ad33aSDoug Rabson 756e97ad33aSDoug Rabson /* Helper routine for checking if fileops are possible on this file */ 757e97ad33aSDoug Rabson static int 758e97ad33aSDoug Rabson p9fs_check_possible(struct vnode *vp, struct vattr *vap, mode_t mode) 759e97ad33aSDoug Rabson { 760e97ad33aSDoug Rabson 761e97ad33aSDoug Rabson /* Check if we are allowed to write */ 762e97ad33aSDoug Rabson switch (vap->va_type) { 763e97ad33aSDoug Rabson case VDIR: 764e97ad33aSDoug Rabson case VLNK: 765e97ad33aSDoug Rabson case VREG: 766e97ad33aSDoug Rabson /* 767e97ad33aSDoug Rabson * Normal nodes: check if we're on a read-only mounted 768e97ad33aSDoug Rabson * file system and bail out if we're trying to write. 769e97ad33aSDoug Rabson */ 770e97ad33aSDoug Rabson if ((mode & VMODIFY_PERMS) && (vp->v_mount->mnt_flag & MNT_RDONLY)) 771e97ad33aSDoug Rabson return (EROFS); 772e97ad33aSDoug Rabson break; 773e97ad33aSDoug Rabson case VBLK: 774e97ad33aSDoug Rabson case VCHR: 775e97ad33aSDoug Rabson case VSOCK: 776e97ad33aSDoug Rabson case VFIFO: 777e97ad33aSDoug Rabson /* 778e97ad33aSDoug Rabson * Special nodes: even on read-only mounted file systems 779e97ad33aSDoug Rabson * these are allowed to be written to if permissions allow. 780e97ad33aSDoug Rabson */ 781e97ad33aSDoug Rabson break; 782e97ad33aSDoug Rabson default: 783e97ad33aSDoug Rabson /* No idea what this is */ 784e97ad33aSDoug Rabson return (EINVAL); 785e97ad33aSDoug Rabson } 786e97ad33aSDoug Rabson 787e97ad33aSDoug Rabson return (0); 788e97ad33aSDoug Rabson } 789e97ad33aSDoug Rabson 790e97ad33aSDoug Rabson /* Check the access permissions of the file. */ 791e97ad33aSDoug Rabson static int 792e97ad33aSDoug Rabson p9fs_access(struct vop_access_args *ap) 793e97ad33aSDoug Rabson { 794e97ad33aSDoug Rabson struct vnode *vp; 795e97ad33aSDoug Rabson accmode_t accmode; 796e97ad33aSDoug Rabson struct ucred *cred; 797e97ad33aSDoug Rabson struct vattr vap; 798e97ad33aSDoug Rabson int error; 799e97ad33aSDoug Rabson 800e97ad33aSDoug Rabson vp = ap->a_vp; 801e97ad33aSDoug Rabson accmode = ap->a_accmode; 802e97ad33aSDoug Rabson cred = ap->a_cred; 803e97ad33aSDoug Rabson 804e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: vp %p\n", __func__, vp); 805e97ad33aSDoug Rabson 806e97ad33aSDoug Rabson /* make sure getattr is working correctly and is defined.*/ 807e97ad33aSDoug Rabson error = VOP_GETATTR(vp, &vap, cred); 808e97ad33aSDoug Rabson if (error != 0) 809e97ad33aSDoug Rabson return (error); 810e97ad33aSDoug Rabson 811e97ad33aSDoug Rabson error = p9fs_check_possible(vp, &vap, accmode); 812e97ad33aSDoug Rabson if (error != 0) 813e97ad33aSDoug Rabson return (error); 814e97ad33aSDoug Rabson 815e97ad33aSDoug Rabson /* Call the Generic Access check in VOPS*/ 816e97ad33aSDoug Rabson error = vaccess(vp->v_type, vap.va_mode, vap.va_uid, vap.va_gid, accmode, 817e97ad33aSDoug Rabson cred); 818e97ad33aSDoug Rabson 819e97ad33aSDoug Rabson 820e97ad33aSDoug Rabson return (error); 821e97ad33aSDoug Rabson } 822e97ad33aSDoug Rabson 823e97ad33aSDoug Rabson /* 824e97ad33aSDoug Rabson * Reload the file stats from the server and update the inode structure present 825e97ad33aSDoug Rabson * in p9fs node. 826e97ad33aSDoug Rabson */ 827e97ad33aSDoug Rabson int 828e97ad33aSDoug Rabson p9fs_reload_stats_dotl(struct vnode *vp, struct ucred *cred) 829e97ad33aSDoug Rabson { 830e97ad33aSDoug Rabson struct p9_stat_dotl *stat; 831e97ad33aSDoug Rabson int error; 832e97ad33aSDoug Rabson struct p9fs_node *node; 833e97ad33aSDoug Rabson struct p9fs_session *vses; 834e97ad33aSDoug Rabson struct p9_fid *vfid; 835e97ad33aSDoug Rabson 836e97ad33aSDoug Rabson error = 0; 837e97ad33aSDoug Rabson node = P9FS_VTON(vp); 838e97ad33aSDoug Rabson vses = node->p9fs_ses; 839e97ad33aSDoug Rabson 840e97ad33aSDoug Rabson vfid = p9fs_get_fid(vses->clnt, node, cred, VOFID, P9PROTO_OREAD, &error); 841e97ad33aSDoug Rabson if (vfid == NULL) { 842e97ad33aSDoug Rabson vfid = p9fs_get_fid(vses->clnt, node, cred, VFID, -1, &error); 843e97ad33aSDoug Rabson if (error) 844e97ad33aSDoug Rabson return (error); 845e97ad33aSDoug Rabson } 846e97ad33aSDoug Rabson 847e97ad33aSDoug Rabson stat = uma_zalloc(p9fs_getattr_zone, M_WAITOK | M_ZERO); 848e97ad33aSDoug Rabson 849e97ad33aSDoug Rabson error = p9_client_getattr(vfid, stat, P9PROTO_STATS_ALL); 850e97ad33aSDoug Rabson if (error != 0) { 851e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: p9_client_getattr failed: %d\n", __func__, error); 852e97ad33aSDoug Rabson goto out; 853e97ad33aSDoug Rabson } 854e97ad33aSDoug Rabson 855e97ad33aSDoug Rabson /* Init the vnode with the disk info */ 856e97ad33aSDoug Rabson p9fs_stat_vnode_dotl(stat, vp); 857e97ad33aSDoug Rabson out: 858e97ad33aSDoug Rabson if (stat != NULL) { 859e97ad33aSDoug Rabson uma_zfree(p9fs_getattr_zone, stat); 860e97ad33aSDoug Rabson } 861e97ad33aSDoug Rabson 862e97ad33aSDoug Rabson return (error); 863e97ad33aSDoug Rabson } 864e97ad33aSDoug Rabson 865e97ad33aSDoug Rabson /* 866e97ad33aSDoug Rabson * Read the current inode values into the vap attr. We reload the stats from 867e97ad33aSDoug Rabson * the server. 868e97ad33aSDoug Rabson */ 869e97ad33aSDoug Rabson static int 870e97ad33aSDoug Rabson p9fs_getattr_dotl(struct vop_getattr_args *ap) 871e97ad33aSDoug Rabson { 872e97ad33aSDoug Rabson struct vnode *vp; 873e97ad33aSDoug Rabson struct vattr *vap; 874e97ad33aSDoug Rabson struct p9fs_node *node; 875e97ad33aSDoug Rabson struct p9fs_inode *inode; 876e97ad33aSDoug Rabson int error; 877e97ad33aSDoug Rabson 878e97ad33aSDoug Rabson vp = ap->a_vp; 879e97ad33aSDoug Rabson vap = ap->a_vap; 880e97ad33aSDoug Rabson node = P9FS_VTON(vp); 881e97ad33aSDoug Rabson 882e97ad33aSDoug Rabson if (node == NULL) 883e97ad33aSDoug Rabson return (ENOENT); 884e97ad33aSDoug Rabson 885e97ad33aSDoug Rabson inode = &node->inode; 886e97ad33aSDoug Rabson 887e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: %u %u\n", __func__, inode->i_mode, IFTOVT(inode->i_mode)); 888e97ad33aSDoug Rabson 889e97ad33aSDoug Rabson /* Reload our stats once to get the right values.*/ 890e97ad33aSDoug Rabson error = p9fs_reload_stats_dotl(vp, ap->a_cred); 891e97ad33aSDoug Rabson if (error != 0) { 892e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: failed: %d\n", __func__, error); 893e97ad33aSDoug Rabson return (error); 894e97ad33aSDoug Rabson } 895e97ad33aSDoug Rabson 896e97ad33aSDoug Rabson /* Basic info */ 897e97ad33aSDoug Rabson VATTR_NULL(vap); 898e97ad33aSDoug Rabson 899e97ad33aSDoug Rabson vap->va_atime.tv_sec = inode->i_atime; 900e97ad33aSDoug Rabson vap->va_mtime.tv_sec = inode->i_mtime; 901e97ad33aSDoug Rabson vap->va_ctime.tv_sec = inode->i_ctime; 902e97ad33aSDoug Rabson vap->va_atime.tv_nsec = inode->i_atime_nsec; 903e97ad33aSDoug Rabson vap->va_mtime.tv_nsec = inode->i_mtime_nsec; 904e97ad33aSDoug Rabson vap->va_ctime.tv_nsec = inode->i_ctime_nsec; 905e97ad33aSDoug Rabson vap->va_type = IFTOVT(inode->i_mode); 906e97ad33aSDoug Rabson vap->va_mode = inode->i_mode; 907e97ad33aSDoug Rabson vap->va_uid = inode->n_uid; 908e97ad33aSDoug Rabson vap->va_gid = inode->n_gid; 909e97ad33aSDoug Rabson vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 910e97ad33aSDoug Rabson vap->va_size = inode->i_size; 911e97ad33aSDoug Rabson vap->va_nlink = inode->i_links_count; 912e97ad33aSDoug Rabson vap->va_blocksize = inode->blksize; 913e97ad33aSDoug Rabson vap->va_fileid = inode->i_qid_path; 914e97ad33aSDoug Rabson vap->va_flags = inode->i_flags; 915e97ad33aSDoug Rabson vap->va_gen = inode->gen; 916e97ad33aSDoug Rabson vap->va_filerev = inode->data_version; 917e97ad33aSDoug Rabson vap->va_vaflags = 0; 918e97ad33aSDoug Rabson vap->va_bytes = inode->blocks * P9PROTO_TGETATTR_BLK; 919e97ad33aSDoug Rabson 920e97ad33aSDoug Rabson return (0); 921e97ad33aSDoug Rabson } 922e97ad33aSDoug Rabson 923e97ad33aSDoug Rabson /* Convert a standard FreeBSD permission to P9. */ 924e97ad33aSDoug Rabson static uint32_t 925e97ad33aSDoug Rabson p9fs_unix2p9_mode(uint32_t mode) 926e97ad33aSDoug Rabson { 927e97ad33aSDoug Rabson uint32_t res; 928e97ad33aSDoug Rabson 929e97ad33aSDoug Rabson res = mode & 0777; 930e97ad33aSDoug Rabson if (S_ISDIR(mode)) 931e97ad33aSDoug Rabson res |= P9PROTO_DMDIR; 932e97ad33aSDoug Rabson if (S_ISSOCK(mode)) 933e97ad33aSDoug Rabson res |= P9PROTO_DMSOCKET; 934e97ad33aSDoug Rabson if (S_ISLNK(mode)) 935e97ad33aSDoug Rabson res |= P9PROTO_DMSYMLINK; 936e97ad33aSDoug Rabson if (S_ISFIFO(mode)) 937e97ad33aSDoug Rabson res |= P9PROTO_DMNAMEDPIPE; 938e97ad33aSDoug Rabson if ((mode & S_ISUID) == S_ISUID) 939e97ad33aSDoug Rabson res |= P9PROTO_DMSETUID; 940e97ad33aSDoug Rabson if ((mode & S_ISGID) == S_ISGID) 941e97ad33aSDoug Rabson res |= P9PROTO_DMSETGID; 942e97ad33aSDoug Rabson if ((mode & S_ISVTX) == S_ISVTX) 943e97ad33aSDoug Rabson res |= P9PROTO_DMSETVTX; 944e97ad33aSDoug Rabson 945e97ad33aSDoug Rabson return (res); 946e97ad33aSDoug Rabson } 947e97ad33aSDoug Rabson 948e97ad33aSDoug Rabson /* Update inode with the stats read from server.(9P2000.L version) */ 949e97ad33aSDoug Rabson int 950e97ad33aSDoug Rabson p9fs_stat_vnode_dotl(struct p9_stat_dotl *stat, struct vnode *vp) 951e97ad33aSDoug Rabson { 952e97ad33aSDoug Rabson struct p9fs_node *np; 953e97ad33aSDoug Rabson struct p9fs_inode *inode; 954e97ad33aSDoug Rabson 955e97ad33aSDoug Rabson np = P9FS_VTON(vp); 956e97ad33aSDoug Rabson inode = &np->inode; 957e97ad33aSDoug Rabson 958e97ad33aSDoug Rabson ASSERT_VOP_LOCKED(vp, __func__); 959e97ad33aSDoug Rabson /* Update the pager size if file size changes on host */ 960e97ad33aSDoug Rabson if (inode->i_size != stat->st_size) { 961e97ad33aSDoug Rabson inode->i_size = stat->st_size; 962e97ad33aSDoug Rabson if (vp->v_type == VREG) 963e97ad33aSDoug Rabson vnode_pager_setsize(vp, inode->i_size); 964e97ad33aSDoug Rabson } 965e97ad33aSDoug Rabson 966e97ad33aSDoug Rabson inode->i_mtime = stat->st_mtime_sec; 967e97ad33aSDoug Rabson inode->i_atime = stat->st_atime_sec; 968e97ad33aSDoug Rabson inode->i_ctime = stat->st_ctime_sec; 969e97ad33aSDoug Rabson inode->i_mtime_nsec = stat->st_mtime_nsec; 970e97ad33aSDoug Rabson inode->i_atime_nsec = stat->st_atime_nsec; 971e97ad33aSDoug Rabson inode->i_ctime_nsec = stat->st_ctime_nsec; 972e97ad33aSDoug Rabson inode->n_uid = stat->st_uid; 973e97ad33aSDoug Rabson inode->n_gid = stat->st_gid; 974e97ad33aSDoug Rabson inode->i_mode = stat->st_mode; 975e97ad33aSDoug Rabson vp->v_type = IFTOVT(inode->i_mode); 976e97ad33aSDoug Rabson inode->i_links_count = stat->st_nlink; 977e97ad33aSDoug Rabson inode->blksize = stat->st_blksize; 978e97ad33aSDoug Rabson inode->blocks = stat->st_blocks; 979e97ad33aSDoug Rabson inode->gen = stat->st_gen; 980e97ad33aSDoug Rabson inode->data_version = stat->st_data_version; 981e97ad33aSDoug Rabson 982e97ad33aSDoug Rabson ASSERT_VOP_LOCKED(vp, __func__); 983e97ad33aSDoug Rabson /* Setting a flag if file changes based on qid version */ 984e97ad33aSDoug Rabson if (np->vqid.qid_version != stat->qid.version) 985e97ad33aSDoug Rabson np->flags |= P9FS_NODE_MODIFIED; 986e97ad33aSDoug Rabson memcpy(&np->vqid, &stat->qid, sizeof(stat->qid)); 987e97ad33aSDoug Rabson 988e97ad33aSDoug Rabson return (0); 989e97ad33aSDoug Rabson } 990e97ad33aSDoug Rabson 991e97ad33aSDoug Rabson /* 992e97ad33aSDoug Rabson * Write the current in memory inode stats into persistent stats structure 993e97ad33aSDoug Rabson * to write to the server(for linux version). 994e97ad33aSDoug Rabson */ 995e97ad33aSDoug Rabson static int 996e97ad33aSDoug Rabson p9fs_inode_to_iattr(struct p9fs_inode *inode, struct p9_iattr_dotl *p9attr) 997e97ad33aSDoug Rabson { 998e97ad33aSDoug Rabson p9attr->size = inode->i_size; 999e97ad33aSDoug Rabson p9attr->mode = inode->i_mode; 1000e97ad33aSDoug Rabson p9attr->uid = inode->n_uid; 1001e97ad33aSDoug Rabson p9attr->gid = inode->n_gid; 1002e97ad33aSDoug Rabson p9attr->atime_sec = inode->i_atime; 1003e97ad33aSDoug Rabson p9attr->atime_nsec = inode->i_atime_nsec; 1004e97ad33aSDoug Rabson p9attr->mtime_sec = inode->i_mtime; 1005e97ad33aSDoug Rabson p9attr->mtime_nsec = inode->i_mtime_nsec; 1006e97ad33aSDoug Rabson 1007e97ad33aSDoug Rabson return (0); 1008e97ad33aSDoug Rabson } 1009e97ad33aSDoug Rabson 1010e97ad33aSDoug Rabson /* 1011e97ad33aSDoug Rabson * Modify the ownership of a file whenever the chown is called on the 1012e97ad33aSDoug Rabson * file. 1013e97ad33aSDoug Rabson */ 1014e97ad33aSDoug Rabson static int 1015e97ad33aSDoug Rabson p9fs_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred, 1016e97ad33aSDoug Rabson struct thread *td) 1017e97ad33aSDoug Rabson { 1018e97ad33aSDoug Rabson struct p9fs_node *np; 1019e97ad33aSDoug Rabson struct p9fs_inode *inode; 1020e97ad33aSDoug Rabson uid_t ouid; 1021e97ad33aSDoug Rabson gid_t ogid; 1022e97ad33aSDoug Rabson int error; 1023e97ad33aSDoug Rabson 1024e97ad33aSDoug Rabson np = P9FS_VTON(vp); 1025e97ad33aSDoug Rabson inode = &np->inode; 1026e97ad33aSDoug Rabson 1027e97ad33aSDoug Rabson if (uid == (uid_t)VNOVAL) 1028e97ad33aSDoug Rabson uid = inode->n_uid; 1029e97ad33aSDoug Rabson if (gid == (gid_t)VNOVAL) 1030e97ad33aSDoug Rabson gid = inode->n_gid; 1031e97ad33aSDoug Rabson /* 1032e97ad33aSDoug Rabson * To modify the ownership of a file, must possess VADMIN for that 1033e97ad33aSDoug Rabson * file. 1034e97ad33aSDoug Rabson */ 1035e97ad33aSDoug Rabson if ((error = VOP_ACCESSX(vp, VWRITE_OWNER, cred, td))) 1036e97ad33aSDoug Rabson return (error); 1037e97ad33aSDoug Rabson /* 1038e97ad33aSDoug Rabson * To change the owner of a file, or change the group of a file to a 1039e97ad33aSDoug Rabson * group of which we are not a member, the caller must have 1040e97ad33aSDoug Rabson * privilege. 1041e97ad33aSDoug Rabson */ 1042e97ad33aSDoug Rabson if (((uid != inode->n_uid && uid != cred->cr_uid) || 1043e97ad33aSDoug Rabson (gid != inode->n_gid && !groupmember(gid, cred))) && 1044e97ad33aSDoug Rabson (error = priv_check_cred(cred, PRIV_VFS_CHOWN))) 1045e97ad33aSDoug Rabson return (error); 1046e97ad33aSDoug Rabson 1047e97ad33aSDoug Rabson ogid = inode->n_gid; 1048e97ad33aSDoug Rabson ouid = inode->n_uid; 1049e97ad33aSDoug Rabson 1050e97ad33aSDoug Rabson inode->n_gid = gid; 1051e97ad33aSDoug Rabson inode->n_uid = uid; 1052e97ad33aSDoug Rabson 1053e97ad33aSDoug Rabson if ((inode->i_mode & (ISUID | ISGID)) && 1054e97ad33aSDoug Rabson (ouid != uid || ogid != gid)) { 1055e97ad33aSDoug Rabson 1056e97ad33aSDoug Rabson if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID)) 1057e97ad33aSDoug Rabson inode->i_mode &= ~(ISUID | ISGID); 1058e97ad33aSDoug Rabson } 1059e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: vp %p, cred %p, td %p - ret OK\n", __func__, vp, cred, td); 1060e97ad33aSDoug Rabson 1061e97ad33aSDoug Rabson return (0); 1062e97ad33aSDoug Rabson } 1063e97ad33aSDoug Rabson 1064e97ad33aSDoug Rabson /* 1065e97ad33aSDoug Rabson * Update the in memory inode with all chmod new permissions/mode. Typically a 1066e97ad33aSDoug Rabson * setattr is called to update it to server. 1067e97ad33aSDoug Rabson */ 1068e97ad33aSDoug Rabson static int 1069e97ad33aSDoug Rabson p9fs_chmod(struct vnode *vp, uint32_t mode, struct ucred *cred, struct thread *td) 1070e97ad33aSDoug Rabson { 1071e97ad33aSDoug Rabson struct p9fs_node *np; 1072e97ad33aSDoug Rabson struct p9fs_inode *inode; 1073e97ad33aSDoug Rabson uint32_t nmode; 1074e97ad33aSDoug Rabson int error; 1075e97ad33aSDoug Rabson 1076e97ad33aSDoug Rabson np = P9FS_VTON(vp); 1077e97ad33aSDoug Rabson inode = &np->inode; 1078e97ad33aSDoug Rabson 1079e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: vp %p, mode %x, cred %p, td %p\n", __func__, vp, mode, cred, td); 1080e97ad33aSDoug Rabson /* 1081e97ad33aSDoug Rabson * To modify the permissions on a file, must possess VADMIN 1082e97ad33aSDoug Rabson * for that file. 1083e97ad33aSDoug Rabson */ 1084e97ad33aSDoug Rabson if ((error = VOP_ACCESS(vp, VADMIN, cred, td))) 1085e97ad33aSDoug Rabson return (error); 1086e97ad33aSDoug Rabson 1087e97ad33aSDoug Rabson /* 1088e97ad33aSDoug Rabson * Privileged processes may set the sticky bit on non-directories, 1089e97ad33aSDoug Rabson * as well as set the setgid bit on a file with a group that the 1090e97ad33aSDoug Rabson * process is not a member of. Both of these are allowed in 1091e97ad33aSDoug Rabson * jail(8). 1092e97ad33aSDoug Rabson */ 1093e97ad33aSDoug Rabson if (vp->v_type != VDIR && (mode & S_ISTXT)) { 1094e97ad33aSDoug Rabson if (priv_check_cred(cred, PRIV_VFS_STICKYFILE)) 1095e97ad33aSDoug Rabson return (EFTYPE); 1096e97ad33aSDoug Rabson } 1097e97ad33aSDoug Rabson if (!groupmember(inode->n_gid, cred) && (mode & ISGID)) { 1098e97ad33aSDoug Rabson error = priv_check_cred(cred, PRIV_VFS_SETGID); 1099e97ad33aSDoug Rabson if (error != 0) 1100e97ad33aSDoug Rabson return (error); 1101e97ad33aSDoug Rabson } 1102e97ad33aSDoug Rabson 1103e97ad33aSDoug Rabson /* 1104e97ad33aSDoug Rabson * Deny setting setuid if we are not the file owner. 1105e97ad33aSDoug Rabson */ 1106e97ad33aSDoug Rabson if ((mode & ISUID) && inode->n_uid != cred->cr_uid) { 1107e97ad33aSDoug Rabson error = priv_check_cred(cred, PRIV_VFS_ADMIN); 1108e97ad33aSDoug Rabson if (error != 0) 1109e97ad33aSDoug Rabson return (error); 1110e97ad33aSDoug Rabson } 1111e97ad33aSDoug Rabson nmode = inode->i_mode; 1112e97ad33aSDoug Rabson nmode &= ~ALLPERMS; 1113e97ad33aSDoug Rabson nmode |= (mode & ALLPERMS); 1114e97ad33aSDoug Rabson inode->i_mode = nmode; 1115e97ad33aSDoug Rabson 1116e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: to mode %x %d \n ", __func__, nmode, error); 1117e97ad33aSDoug Rabson 1118e97ad33aSDoug Rabson return (error); 1119e97ad33aSDoug Rabson } 1120e97ad33aSDoug Rabson 1121e97ad33aSDoug Rabson /* 1122e97ad33aSDoug Rabson * Set the attributes of a file referenced by fid. A valid bitmask is sent 1123e97ad33aSDoug Rabson * in request selecting which fields to set 1124e97ad33aSDoug Rabson */ 1125e97ad33aSDoug Rabson static int 1126e97ad33aSDoug Rabson p9fs_setattr_dotl(struct vop_setattr_args *ap) 1127e97ad33aSDoug Rabson { 1128e97ad33aSDoug Rabson struct vnode *vp; 1129e97ad33aSDoug Rabson struct vattr *vap; 1130e97ad33aSDoug Rabson struct p9fs_node *node; 1131e97ad33aSDoug Rabson struct p9fs_inode *inode; 1132e97ad33aSDoug Rabson struct ucred *cred; 1133e97ad33aSDoug Rabson struct thread *td; 1134e97ad33aSDoug Rabson struct p9_iattr_dotl *p9attr; 1135e97ad33aSDoug Rabson struct p9fs_session *vses; 1136e97ad33aSDoug Rabson struct p9_fid *vfid; 1137e97ad33aSDoug Rabson uint64_t oldfilesize; 1138e97ad33aSDoug Rabson int error; 1139e97ad33aSDoug Rabson 1140e97ad33aSDoug Rabson vp = ap->a_vp; 1141e97ad33aSDoug Rabson vap = ap->a_vap; 1142e97ad33aSDoug Rabson node = P9FS_VTON(vp); 1143e97ad33aSDoug Rabson inode = &node->inode; 1144e97ad33aSDoug Rabson cred = ap->a_cred; 1145e97ad33aSDoug Rabson td = curthread; 1146e97ad33aSDoug Rabson vses = node->p9fs_ses; 1147e97ad33aSDoug Rabson error = 0; 1148e97ad33aSDoug Rabson 1149e97ad33aSDoug Rabson if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || 1150e97ad33aSDoug Rabson (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || 1151e97ad33aSDoug Rabson (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || 1152e97ad33aSDoug Rabson (vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { 1153e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: unsettable attribute\n", __func__); 1154e97ad33aSDoug Rabson return (EINVAL); 1155e97ad33aSDoug Rabson } 1156e97ad33aSDoug Rabson /* Disallow write attempts on read only filesystem */ 1157e97ad33aSDoug Rabson if (vp->v_mount->mnt_flag & MNT_RDONLY) 1158e97ad33aSDoug Rabson return (EROFS); 1159e97ad33aSDoug Rabson 1160e97ad33aSDoug Rabson /* Setting of flags is not supported */ 1161e97ad33aSDoug Rabson if (vap->va_flags != VNOVAL) 1162e97ad33aSDoug Rabson return (EOPNOTSUPP); 1163e97ad33aSDoug Rabson 1164e97ad33aSDoug Rabson /* Allocate p9attr struct */ 1165e97ad33aSDoug Rabson p9attr = uma_zalloc(p9fs_setattr_zone, M_WAITOK | M_ZERO); 1166e97ad33aSDoug Rabson if (p9attr == NULL) 1167e97ad33aSDoug Rabson return (ENOMEM); 1168e97ad33aSDoug Rabson 1169e97ad33aSDoug Rabson /* Check if we need to change the ownership of the file*/ 1170e97ad33aSDoug Rabson if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { 1171e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: vp:%p td:%p uid/gid %x/%x\n", __func__, 1172e97ad33aSDoug Rabson vp, td, vap->va_uid, vap->va_gid); 1173e97ad33aSDoug Rabson 1174e97ad33aSDoug Rabson error = p9fs_chown(vp, vap->va_uid, vap->va_gid, cred, td); 1175e97ad33aSDoug Rabson p9attr->valid |= P9PROTO_SETATTR_UID | P9PROTO_SETATTR_GID | 1176e97ad33aSDoug Rabson P9PROTO_SETATTR_MODE; 1177e97ad33aSDoug Rabson if (error) 1178e97ad33aSDoug Rabson goto out; 1179e97ad33aSDoug Rabson } 1180e97ad33aSDoug Rabson 1181e97ad33aSDoug Rabson /* Check for mode changes */ 1182e97ad33aSDoug Rabson if (vap->va_mode != (mode_t)VNOVAL) { 1183e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: vp:%p td:%p mode %x\n", __func__, vp, td, 1184e97ad33aSDoug Rabson vap->va_mode); 1185e97ad33aSDoug Rabson 1186e97ad33aSDoug Rabson error = p9fs_chmod(vp, (int)vap->va_mode, cred, td); 1187e97ad33aSDoug Rabson p9attr->valid |= P9PROTO_SETATTR_MODE; 1188e97ad33aSDoug Rabson if (error) 1189e97ad33aSDoug Rabson goto out; 1190e97ad33aSDoug Rabson } 1191e97ad33aSDoug Rabson 1192e97ad33aSDoug Rabson /* Update the size of the file and update mtime */ 1193e97ad33aSDoug Rabson if (vap->va_size != (uint64_t)VNOVAL) { 1194e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: vp:%p td:%p size:%jx\n", __func__, 1195e97ad33aSDoug Rabson vp, td, (uintmax_t)vap->va_size); 1196e97ad33aSDoug Rabson switch (vp->v_type) { 1197e97ad33aSDoug Rabson case VDIR: 1198e97ad33aSDoug Rabson error = EISDIR; 1199e97ad33aSDoug Rabson goto out; 1200e97ad33aSDoug Rabson case VLNK: 1201e97ad33aSDoug Rabson case VREG: 1202e97ad33aSDoug Rabson /* Invalidate cached pages of vp */ 1203e97ad33aSDoug Rabson error = vinvalbuf(vp, 0, 0, 0); 1204e97ad33aSDoug Rabson if (error) 1205e97ad33aSDoug Rabson goto out; 1206e97ad33aSDoug Rabson oldfilesize = inode->i_size; 1207e97ad33aSDoug Rabson inode->i_size = vap->va_size; 1208e97ad33aSDoug Rabson /* Update the p9fs_inode time */ 1209e97ad33aSDoug Rabson p9fs_itimes(vp); 1210e97ad33aSDoug Rabson p9attr->valid |= P9PROTO_SETATTR_SIZE | 1211e97ad33aSDoug Rabson P9PROTO_SETATTR_ATIME | 1212e97ad33aSDoug Rabson P9PROTO_SETATTR_MTIME | 1213e97ad33aSDoug Rabson P9PROTO_SETATTR_ATIME_SET | 1214e97ad33aSDoug Rabson P9PROTO_SETATTR_MTIME_SET ; 1215e97ad33aSDoug Rabson break; 1216e97ad33aSDoug Rabson default: 1217e97ad33aSDoug Rabson goto out; 1218e97ad33aSDoug Rabson } 1219e97ad33aSDoug Rabson } else if (vap->va_atime.tv_sec != VNOVAL || 1220e97ad33aSDoug Rabson vap->va_mtime.tv_sec != VNOVAL) { 1221e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: vp:%p td:%p time a/m %jx/%jx/\n", 1222e97ad33aSDoug Rabson __func__, vp, td, (uintmax_t)vap->va_atime.tv_sec, 1223e97ad33aSDoug Rabson (uintmax_t)vap->va_mtime.tv_sec); 1224e97ad33aSDoug Rabson /* Update the p9fs_inode times */ 1225e97ad33aSDoug Rabson p9fs_itimes(vp); 1226e97ad33aSDoug Rabson p9attr->valid |= P9PROTO_SETATTR_ATIME | 1227e97ad33aSDoug Rabson P9PROTO_SETATTR_MTIME | P9PROTO_SETATTR_ATIME_SET | 1228e97ad33aSDoug Rabson P9PROTO_SETATTR_MTIME_SET; 1229e97ad33aSDoug Rabson } 1230e97ad33aSDoug Rabson 1231e97ad33aSDoug Rabson vfid = p9fs_get_fid(vses->clnt, node, cred, VOFID, P9PROTO_OWRITE, &error); 1232e97ad33aSDoug Rabson if (vfid == NULL) { 1233e97ad33aSDoug Rabson vfid = p9fs_get_fid(vses->clnt, node, cred, VFID, -1, &error); 1234e97ad33aSDoug Rabson if (error) 1235e97ad33aSDoug Rabson goto out; 1236e97ad33aSDoug Rabson } 1237e97ad33aSDoug Rabson 1238e97ad33aSDoug Rabson /* Write the inode structure values into p9attr */ 1239e97ad33aSDoug Rabson p9fs_inode_to_iattr(inode, p9attr); 1240e97ad33aSDoug Rabson error = p9_client_setattr(vfid, p9attr); 1241e97ad33aSDoug Rabson if (vap->va_size != (uint64_t)VNOVAL && vp->v_type == VREG) { 1242e97ad33aSDoug Rabson if (error) 1243e97ad33aSDoug Rabson inode->i_size = oldfilesize; 1244e97ad33aSDoug Rabson else 1245e97ad33aSDoug Rabson vnode_pager_setsize(vp, inode->i_size); 1246e97ad33aSDoug Rabson } 1247e97ad33aSDoug Rabson out: 1248e97ad33aSDoug Rabson if (p9attr) { 1249e97ad33aSDoug Rabson uma_zfree(p9fs_setattr_zone, p9attr); 1250e97ad33aSDoug Rabson } 1251e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: error: %d\n", __func__, error); 1252e97ad33aSDoug Rabson return (error); 1253e97ad33aSDoug Rabson } 1254e97ad33aSDoug Rabson 1255e97ad33aSDoug Rabson struct open_fid_state { 1256e97ad33aSDoug Rabson struct p9_fid *vofid; 1257e97ad33aSDoug Rabson int fflags; 1258e97ad33aSDoug Rabson int opened; 1259e97ad33aSDoug Rabson }; 1260e97ad33aSDoug Rabson 1261e97ad33aSDoug Rabson /* 1262e97ad33aSDoug Rabson * TODO: change this to take P9PROTO_* mode and avoid routing through 1263e97ad33aSDoug Rabson * VOP_OPEN, factoring out implementation of p9fs_open. 1264e97ad33aSDoug Rabson */ 1265e97ad33aSDoug Rabson static int 1266e97ad33aSDoug Rabson p9fs_get_open_fid(struct vnode *vp, int fflags, struct ucred *cr, struct open_fid_state *statep) 1267e97ad33aSDoug Rabson { 1268e97ad33aSDoug Rabson struct p9fs_node *np; 1269e97ad33aSDoug Rabson struct p9fs_session *vses; 1270e97ad33aSDoug Rabson struct p9_fid *vofid; 1271e97ad33aSDoug Rabson int mode = p9fs_uflags_mode(fflags, TRUE); 1272e97ad33aSDoug Rabson int error = 0; 1273e97ad33aSDoug Rabson 1274e97ad33aSDoug Rabson statep->opened = FALSE; 1275e97ad33aSDoug Rabson 1276e97ad33aSDoug Rabson np = P9FS_VTON(vp); 1277e97ad33aSDoug Rabson vses = np->p9fs_ses; 1278e97ad33aSDoug Rabson vofid = p9fs_get_fid(vses->clnt, np, cr, VOFID, mode, &error); 1279e97ad33aSDoug Rabson if (vofid == NULL) { 1280e97ad33aSDoug Rabson error = VOP_OPEN(vp, fflags, cr, curthread, NULL); 1281e97ad33aSDoug Rabson if (error) { 1282e97ad33aSDoug Rabson return (error); 1283e97ad33aSDoug Rabson } 1284e97ad33aSDoug Rabson vofid = p9fs_get_fid(vses->clnt, np, cr, VOFID, mode, &error); 1285e97ad33aSDoug Rabson if (vofid == NULL) { 1286e97ad33aSDoug Rabson return (EBADF); 1287e97ad33aSDoug Rabson } 1288e97ad33aSDoug Rabson statep->fflags = fflags; 1289e97ad33aSDoug Rabson statep->opened = TRUE; 1290e97ad33aSDoug Rabson } 1291e97ad33aSDoug Rabson statep->vofid = vofid; 1292e97ad33aSDoug Rabson return (0); 1293e97ad33aSDoug Rabson } 1294e97ad33aSDoug Rabson 1295e97ad33aSDoug Rabson static void 1296e97ad33aSDoug Rabson p9fs_release_open_fid(struct vnode *vp, struct ucred *cr, struct open_fid_state *statep) 1297e97ad33aSDoug Rabson { 1298e97ad33aSDoug Rabson if (statep->opened) { 1299e97ad33aSDoug Rabson (void) VOP_CLOSE(vp, statep->fflags, cr, curthread); 1300e97ad33aSDoug Rabson } 1301e97ad33aSDoug Rabson } 1302e97ad33aSDoug Rabson 1303e97ad33aSDoug Rabson /* 1304e97ad33aSDoug Rabson * An I/O buffer is used to to do any transfer. The uio is the vfs structure we 1305e97ad33aSDoug Rabson * need to copy data into. As long as resid is greater than zero, we call 1306e97ad33aSDoug Rabson * client_read to read data from offset(offset into the file) in the open fid 1307e97ad33aSDoug Rabson * for the file into the I/O buffer. The data is read into the user data buffer. 1308e97ad33aSDoug Rabson */ 1309e97ad33aSDoug Rabson static int 1310e97ad33aSDoug Rabson p9fs_read(struct vop_read_args *ap) 1311e97ad33aSDoug Rabson { 1312e97ad33aSDoug Rabson struct vnode *vp; 1313e97ad33aSDoug Rabson struct uio *uio; 1314e97ad33aSDoug Rabson struct p9fs_node *np; 1315e97ad33aSDoug Rabson uint64_t offset; 1316e97ad33aSDoug Rabson int64_t ret; 1317e97ad33aSDoug Rabson uint64_t resid; 1318e97ad33aSDoug Rabson uint32_t count; 1319e97ad33aSDoug Rabson int error; 1320e97ad33aSDoug Rabson char *io_buffer = NULL; 1321e97ad33aSDoug Rabson uint64_t filesize; 1322e97ad33aSDoug Rabson struct open_fid_state ostate; 1323e97ad33aSDoug Rabson 1324e97ad33aSDoug Rabson vp = ap->a_vp; 1325e97ad33aSDoug Rabson uio = ap->a_uio; 1326e97ad33aSDoug Rabson np = P9FS_VTON(vp); 1327e97ad33aSDoug Rabson error = 0; 1328e97ad33aSDoug Rabson 1329e97ad33aSDoug Rabson if (vp->v_type == VCHR || vp->v_type == VBLK) 1330e97ad33aSDoug Rabson return (EOPNOTSUPP); 1331e97ad33aSDoug Rabson if (vp->v_type != VREG) 1332e97ad33aSDoug Rabson return (EISDIR); 1333e97ad33aSDoug Rabson if (uio->uio_resid == 0) 1334e97ad33aSDoug Rabson return (0); 1335e97ad33aSDoug Rabson if (uio->uio_offset < 0) 1336e97ad33aSDoug Rabson return (EINVAL); 1337e97ad33aSDoug Rabson 1338e97ad33aSDoug Rabson error = p9fs_get_open_fid(vp, FREAD, ap->a_cred, &ostate); 1339e97ad33aSDoug Rabson if (error) 1340e97ad33aSDoug Rabson return (error); 1341e97ad33aSDoug Rabson 1342e97ad33aSDoug Rabson /* where in the file are we to start reading */ 1343e97ad33aSDoug Rabson offset = uio->uio_offset; 1344e97ad33aSDoug Rabson filesize = np->inode.i_size; 1345e97ad33aSDoug Rabson if (uio->uio_offset >= filesize) 1346e97ad33aSDoug Rabson goto out; 1347e97ad33aSDoug Rabson 1348e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: called %jd at %ju\n", 1349e97ad33aSDoug Rabson __func__, (intmax_t)uio->uio_resid, (uintmax_t)uio->uio_offset); 1350e97ad33aSDoug Rabson 1351e97ad33aSDoug Rabson /* Work with a local buffer from the pool for this vop */ 1352e97ad33aSDoug Rabson 1353e97ad33aSDoug Rabson io_buffer = uma_zalloc(p9fs_io_buffer_zone, M_WAITOK | M_ZERO); 1354e97ad33aSDoug Rabson while ((resid = uio->uio_resid) > 0) { 1355e97ad33aSDoug Rabson if (offset >= filesize) 1356e97ad33aSDoug Rabson break; 1357e97ad33aSDoug Rabson count = MIN(filesize - uio->uio_offset , resid); 1358e97ad33aSDoug Rabson if (count == 0) 1359e97ad33aSDoug Rabson break; 1360e97ad33aSDoug Rabson 1361e97ad33aSDoug Rabson /* Copy count bytes into the uio */ 1362e97ad33aSDoug Rabson ret = p9_client_read(ostate.vofid, offset, count, io_buffer); 1363e97ad33aSDoug Rabson /* 1364e97ad33aSDoug Rabson * This is the only place in the entire p9fs where we check the 1365e97ad33aSDoug Rabson * error for < 0 as p9_client_read/write return the number of 1366e97ad33aSDoug Rabson * bytes instead of an error code. In this case if ret is < 0, 1367e97ad33aSDoug Rabson * it means there is an IO error. 1368e97ad33aSDoug Rabson */ 1369e97ad33aSDoug Rabson if (ret < 0) { 1370e97ad33aSDoug Rabson error = -ret; 1371e97ad33aSDoug Rabson goto out; 1372e97ad33aSDoug Rabson } 1373e97ad33aSDoug Rabson error = uiomove(io_buffer, ret, uio); 1374e97ad33aSDoug Rabson if (error != 0) 1375e97ad33aSDoug Rabson goto out; 1376e97ad33aSDoug Rabson 1377e97ad33aSDoug Rabson offset += ret; 1378e97ad33aSDoug Rabson } 1379e97ad33aSDoug Rabson uio->uio_offset = offset; 1380e97ad33aSDoug Rabson out: 1381e97ad33aSDoug Rabson uma_zfree(p9fs_io_buffer_zone, io_buffer); 1382e97ad33aSDoug Rabson p9fs_release_open_fid(vp, ap->a_cred, &ostate); 1383e97ad33aSDoug Rabson 1384e97ad33aSDoug Rabson return (error); 1385e97ad33aSDoug Rabson } 1386e97ad33aSDoug Rabson 1387e97ad33aSDoug Rabson /* 1388e97ad33aSDoug Rabson * The user buffer contains the data to be written. This data is copied first 1389e97ad33aSDoug Rabson * from uio into I/O buffer. This I/O buffer is used to do the client_write to 1390e97ad33aSDoug Rabson * the fid of the file starting from the offset given upto count bytes. The 1391e97ad33aSDoug Rabson * number of bytes written is returned to the caller. 1392e97ad33aSDoug Rabson */ 1393e97ad33aSDoug Rabson static int 1394e97ad33aSDoug Rabson p9fs_write(struct vop_write_args *ap) 1395e97ad33aSDoug Rabson { 1396e97ad33aSDoug Rabson struct vnode *vp; 1397e97ad33aSDoug Rabson struct uio *uio; 1398e97ad33aSDoug Rabson struct p9fs_node *np; 1399e97ad33aSDoug Rabson uint64_t off, offset; 1400e97ad33aSDoug Rabson int64_t ret; 1401e97ad33aSDoug Rabson uint64_t resid, bytes_written; 1402e97ad33aSDoug Rabson uint32_t count; 1403e97ad33aSDoug Rabson int error, ioflag; 1404e97ad33aSDoug Rabson uint64_t file_size; 1405e97ad33aSDoug Rabson char *io_buffer = NULL; 1406e97ad33aSDoug Rabson struct open_fid_state ostate; 1407e97ad33aSDoug Rabson 1408e97ad33aSDoug Rabson vp = ap->a_vp; 1409e97ad33aSDoug Rabson uio = ap->a_uio; 1410e97ad33aSDoug Rabson np = P9FS_VTON(vp); 1411e97ad33aSDoug Rabson error = 0; 1412e97ad33aSDoug Rabson ioflag = ap->a_ioflag; 1413e97ad33aSDoug Rabson 1414e97ad33aSDoug Rabson error = p9fs_get_open_fid(vp, FWRITE, ap->a_cred, &ostate); 1415e97ad33aSDoug Rabson if (error) 1416e97ad33aSDoug Rabson return (error); 1417e97ad33aSDoug Rabson 1418e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: %#zx at %#jx\n", 1419e97ad33aSDoug Rabson __func__, uio->uio_resid, (uintmax_t)uio->uio_offset); 1420e97ad33aSDoug Rabson 1421e97ad33aSDoug Rabson if (uio->uio_offset < 0) { 1422e97ad33aSDoug Rabson error = EINVAL; 1423e97ad33aSDoug Rabson goto out; 1424e97ad33aSDoug Rabson } 1425e97ad33aSDoug Rabson if (uio->uio_resid == 0) 1426e97ad33aSDoug Rabson goto out; 1427e97ad33aSDoug Rabson 1428e97ad33aSDoug Rabson file_size = np->inode.i_size; 1429e97ad33aSDoug Rabson 1430e97ad33aSDoug Rabson switch (vp->v_type) { 1431e97ad33aSDoug Rabson case VREG: 1432e97ad33aSDoug Rabson if (ioflag & IO_APPEND) 1433e97ad33aSDoug Rabson uio->uio_offset = file_size; 1434e97ad33aSDoug Rabson break; 1435e97ad33aSDoug Rabson case VDIR: 1436e97ad33aSDoug Rabson return (EISDIR); 1437e97ad33aSDoug Rabson case VLNK: 1438e97ad33aSDoug Rabson break; 1439e97ad33aSDoug Rabson default: 1440e97ad33aSDoug Rabson panic("%s: bad file type vp: %p", __func__, vp); 1441e97ad33aSDoug Rabson } 1442e97ad33aSDoug Rabson 1443e97ad33aSDoug Rabson resid = uio->uio_resid; 1444e97ad33aSDoug Rabson offset = uio->uio_offset; 1445e97ad33aSDoug Rabson bytes_written = 0; 1446e97ad33aSDoug Rabson error = 0; 1447e97ad33aSDoug Rabson 1448e97ad33aSDoug Rabson io_buffer = uma_zalloc(p9fs_io_buffer_zone, M_WAITOK | M_ZERO); 1449e97ad33aSDoug Rabson while ((resid = uio->uio_resid) > 0) { 1450e97ad33aSDoug Rabson off = 0; 1451e97ad33aSDoug Rabson count = MIN(resid, P9FS_IOUNIT); 1452e97ad33aSDoug Rabson error = uiomove(io_buffer, count, uio); 1453e97ad33aSDoug Rabson 1454e97ad33aSDoug Rabson if (error != 0) { 1455e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: uiomove failed: %d\n", __func__, error); 1456e97ad33aSDoug Rabson goto out; 1457e97ad33aSDoug Rabson } 1458e97ad33aSDoug Rabson 1459e97ad33aSDoug Rabson /* While count still exists, keep writing.*/ 1460e97ad33aSDoug Rabson while (count > 0) { 1461e97ad33aSDoug Rabson /* Copy count bytes from the uio */ 1462e97ad33aSDoug Rabson ret = p9_client_write(ostate.vofid, offset, count, 1463e97ad33aSDoug Rabson io_buffer + off); 1464e97ad33aSDoug Rabson if (ret < 0) { 1465e97ad33aSDoug Rabson if (bytes_written == 0) { 1466e97ad33aSDoug Rabson error = -ret; 1467e97ad33aSDoug Rabson goto out; 1468e97ad33aSDoug Rabson } else { 1469e97ad33aSDoug Rabson break; 1470e97ad33aSDoug Rabson } 1471e97ad33aSDoug Rabson } 1472e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: write %#zx at %#jx\n", 1473e97ad33aSDoug Rabson __func__, uio->uio_resid, (uintmax_t)uio->uio_offset); 1474e97ad33aSDoug Rabson 1475e97ad33aSDoug Rabson off += ret; 1476e97ad33aSDoug Rabson offset += ret; 1477e97ad33aSDoug Rabson bytes_written += ret; 1478e97ad33aSDoug Rabson count -= ret; 1479e97ad33aSDoug Rabson } 1480e97ad33aSDoug Rabson } 1481e97ad33aSDoug Rabson /* Update the fields in the node to reflect the change*/ 1482e97ad33aSDoug Rabson if (file_size < uio->uio_offset + uio->uio_resid) { 1483e97ad33aSDoug Rabson np->inode.i_size = uio->uio_offset + uio->uio_resid; 1484e97ad33aSDoug Rabson vnode_pager_setsize(vp, uio->uio_offset + uio->uio_resid); 1485e97ad33aSDoug Rabson } 1486e97ad33aSDoug Rabson out: 1487e97ad33aSDoug Rabson if (io_buffer) 1488e97ad33aSDoug Rabson uma_zfree(p9fs_io_buffer_zone, io_buffer); 1489e97ad33aSDoug Rabson p9fs_release_open_fid(vp, ap->a_cred, &ostate); 1490e97ad33aSDoug Rabson 1491e97ad33aSDoug Rabson return (error); 1492e97ad33aSDoug Rabson } 1493e97ad33aSDoug Rabson 1494e97ad33aSDoug Rabson /* 1495e97ad33aSDoug Rabson * Common handler of all removal-related VOPs (e.g. rmdir, rm). Perform the 1496e97ad33aSDoug Rabson * client_remove op to send messages to remove the node's fid on the server. 1497e97ad33aSDoug Rabson * After that, does a node metadata cleanup on client side. 1498e97ad33aSDoug Rabson */ 1499e97ad33aSDoug Rabson static int 1500*1d99e8d9SMark Johnston remove_common(struct p9fs_node *dnp, struct p9fs_node *np, const char *name, 1501*1d99e8d9SMark Johnston struct ucred *cred) 1502e97ad33aSDoug Rabson { 1503e97ad33aSDoug Rabson int error; 1504e97ad33aSDoug Rabson struct p9fs_session *vses; 1505e97ad33aSDoug Rabson struct vnode *vp; 1506e97ad33aSDoug Rabson struct p9_fid *vfid; 1507e97ad33aSDoug Rabson 1508e97ad33aSDoug Rabson error = 0; 1509e97ad33aSDoug Rabson vses = np->p9fs_ses; 1510e97ad33aSDoug Rabson vp = P9FS_NTOV(np); 1511e97ad33aSDoug Rabson 1512*1d99e8d9SMark Johnston vfid = p9fs_get_fid(vses->clnt, dnp, cred, VFID, -1, &error); 1513e97ad33aSDoug Rabson if (error != 0) 1514e97ad33aSDoug Rabson return (error); 1515e97ad33aSDoug Rabson 1516*1d99e8d9SMark Johnston error = p9_client_unlink(vfid, name, 1517*1d99e8d9SMark Johnston np->v_node->v_type == VDIR ? P9PROTO_UNLINKAT_REMOVEDIR : 0); 1518e97ad33aSDoug Rabson if (error != 0) 1519e97ad33aSDoug Rabson return (error); 1520e97ad33aSDoug Rabson 1521e97ad33aSDoug Rabson /* Remove all non-open fids associated with the vp */ 1522*1d99e8d9SMark Johnston if (np->inode.i_links_count == 1) 1523e97ad33aSDoug Rabson p9fs_fid_remove_all(np, TRUE); 1524e97ad33aSDoug Rabson 1525e97ad33aSDoug Rabson /* Invalidate all entries of vnode from name cache and hash list. */ 1526e97ad33aSDoug Rabson cache_purge(vp); 1527e97ad33aSDoug Rabson vfs_hash_remove(vp); 1528*1d99e8d9SMark Johnston 1529e97ad33aSDoug Rabson np->flags |= P9FS_NODE_DELETED; 1530e97ad33aSDoug Rabson 1531e97ad33aSDoug Rabson return (error); 1532e97ad33aSDoug Rabson } 1533e97ad33aSDoug Rabson 1534e97ad33aSDoug Rabson /* Remove vop for all files. Call common code for remove and adjust links */ 1535e97ad33aSDoug Rabson static int 1536e97ad33aSDoug Rabson p9fs_remove(struct vop_remove_args *ap) 1537e97ad33aSDoug Rabson { 1538e97ad33aSDoug Rabson struct vnode *vp; 1539e97ad33aSDoug Rabson struct p9fs_node *np; 1540e97ad33aSDoug Rabson struct vnode *dvp; 1541e97ad33aSDoug Rabson struct p9fs_node *dnp; 1542e97ad33aSDoug Rabson struct p9fs_inode *dinode; 1543*1d99e8d9SMark Johnston struct componentname *cnp; 1544e97ad33aSDoug Rabson int error; 1545e97ad33aSDoug Rabson 1546*1d99e8d9SMark Johnston cnp = ap->a_cnp; 1547e97ad33aSDoug Rabson vp = ap->a_vp; 1548e97ad33aSDoug Rabson np = P9FS_VTON(vp); 1549e97ad33aSDoug Rabson dvp = ap->a_dvp; 1550e97ad33aSDoug Rabson dnp = P9FS_VTON(dvp); 1551e97ad33aSDoug Rabson dinode = &dnp->inode; 1552e97ad33aSDoug Rabson 1553e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: vp %p node %p \n", __func__, vp, np); 1554e97ad33aSDoug Rabson 1555e97ad33aSDoug Rabson if (vp->v_type == VDIR) 1556e97ad33aSDoug Rabson return (EISDIR); 1557e97ad33aSDoug Rabson 1558*1d99e8d9SMark Johnston error = remove_common(dnp, np, cnp->cn_nameptr, cnp->cn_cred); 1559e97ad33aSDoug Rabson if (error == 0) 1560e97ad33aSDoug Rabson P9FS_DECR_LINKS(dinode); 1561e97ad33aSDoug Rabson 1562e97ad33aSDoug Rabson return (error); 1563e97ad33aSDoug Rabson } 1564e97ad33aSDoug Rabson 1565e97ad33aSDoug Rabson /* Remove vop for all directories. Call common code for remove and adjust links */ 1566e97ad33aSDoug Rabson static int 1567e97ad33aSDoug Rabson p9fs_rmdir(struct vop_rmdir_args *ap) 1568e97ad33aSDoug Rabson { 1569e97ad33aSDoug Rabson struct vnode *vp; 1570e97ad33aSDoug Rabson struct p9fs_node *np; 1571e97ad33aSDoug Rabson struct vnode *dvp; 1572e97ad33aSDoug Rabson struct p9fs_node *dnp; 1573e97ad33aSDoug Rabson struct p9fs_inode *dinode; 1574*1d99e8d9SMark Johnston struct componentname *cnp; 1575e97ad33aSDoug Rabson int error; 1576e97ad33aSDoug Rabson 1577*1d99e8d9SMark Johnston cnp = ap->a_cnp; 1578e97ad33aSDoug Rabson vp = ap->a_vp; 1579e97ad33aSDoug Rabson np = P9FS_VTON(vp); 1580e97ad33aSDoug Rabson dvp = ap->a_dvp; 1581e97ad33aSDoug Rabson dnp = P9FS_VTON(dvp); 1582e97ad33aSDoug Rabson dinode = &dnp->inode; 1583e97ad33aSDoug Rabson 1584e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: vp %p node %p \n", __func__, vp, np); 1585e97ad33aSDoug Rabson 1586*1d99e8d9SMark Johnston error = remove_common(dnp, np, cnp->cn_nameptr, cnp->cn_cred); 1587e97ad33aSDoug Rabson if (error == 0) 1588e97ad33aSDoug Rabson P9FS_DECR_LINKS(dinode); 1589e97ad33aSDoug Rabson 1590e97ad33aSDoug Rabson return (error); 1591e97ad33aSDoug Rabson } 1592e97ad33aSDoug Rabson 1593e97ad33aSDoug Rabson /* 1594e97ad33aSDoug Rabson * Create symlinks. Make the permissions and call create_common code 1595e97ad33aSDoug Rabson * for Soft links. 1596e97ad33aSDoug Rabson */ 1597e97ad33aSDoug Rabson static int 1598e97ad33aSDoug Rabson p9fs_symlink(struct vop_symlink_args *ap) 1599e97ad33aSDoug Rabson { 1600e97ad33aSDoug Rabson struct vnode *dvp; 1601e97ad33aSDoug Rabson struct vnode **vpp; 1602e97ad33aSDoug Rabson struct vattr *vap; 1603e97ad33aSDoug Rabson struct componentname *cnp; 1604e97ad33aSDoug Rabson char *symtgt; 1605e97ad33aSDoug Rabson struct p9fs_node *dnp; 1606e97ad33aSDoug Rabson struct p9fs_session *vses; 1607e97ad33aSDoug Rabson struct mount *mp; 1608e97ad33aSDoug Rabson struct p9_fid *dvfid, *newfid; 1609e97ad33aSDoug Rabson int error; 1610e97ad33aSDoug Rabson char tmpchr; 1611e97ad33aSDoug Rabson gid_t gid; 1612e97ad33aSDoug Rabson 1613e97ad33aSDoug Rabson dvp = ap->a_dvp; 1614e97ad33aSDoug Rabson vpp = ap->a_vpp; 1615e97ad33aSDoug Rabson vap = ap->a_vap; 1616e97ad33aSDoug Rabson cnp = ap->a_cnp; 1617e97ad33aSDoug Rabson symtgt = (char*)(uintptr_t) ap->a_target; 1618e97ad33aSDoug Rabson dnp = P9FS_VTON(dvp); 1619e97ad33aSDoug Rabson vses = dnp->p9fs_ses; 1620e97ad33aSDoug Rabson mp = vses->p9fs_mount; 1621e97ad33aSDoug Rabson newfid = NULL; 1622e97ad33aSDoug Rabson error = 0; 1623e97ad33aSDoug Rabson gid = vap->va_gid; 1624e97ad33aSDoug Rabson 1625e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: dvp %p\n", __func__, dvp); 1626e97ad33aSDoug Rabson 1627e97ad33aSDoug Rabson /* 1628e97ad33aSDoug Rabson * Save the character present at namelen in nameptr string and 1629e97ad33aSDoug Rabson * null terminate the character to get the search name for p9_dir_walk 1630e97ad33aSDoug Rabson */ 1631e97ad33aSDoug Rabson tmpchr = cnp->cn_nameptr[cnp->cn_namelen]; 1632e97ad33aSDoug Rabson cnp->cn_nameptr[cnp->cn_namelen] = '\0'; 1633e97ad33aSDoug Rabson 1634e97ad33aSDoug Rabson dvfid = p9fs_get_fid(vses->clnt, dnp, cnp->cn_cred, VFID, -1, &error); 1635e97ad33aSDoug Rabson if (error != 0) 1636e97ad33aSDoug Rabson goto out; 1637e97ad33aSDoug Rabson 1638e97ad33aSDoug Rabson error = p9_create_symlink(dvfid, cnp->cn_nameptr, symtgt, gid); 1639e97ad33aSDoug Rabson if (error != 0) 1640e97ad33aSDoug Rabson goto out; 1641e97ad33aSDoug Rabson 1642e97ad33aSDoug Rabson /*create vnode for symtgt */ 1643e97ad33aSDoug Rabson newfid = p9_client_walk(dvfid, 1, &cnp->cn_nameptr, 1, &error); 1644e97ad33aSDoug Rabson if (newfid != NULL) { 1645e97ad33aSDoug Rabson error = p9fs_vget_common(mp, NULL, cnp->cn_lkflags, 1646e97ad33aSDoug Rabson dnp, newfid, vpp, cnp->cn_nameptr); 1647e97ad33aSDoug Rabson if (error != 0) 1648e97ad33aSDoug Rabson goto out; 1649e97ad33aSDoug Rabson } else 1650e97ad33aSDoug Rabson goto out; 1651e97ad33aSDoug Rabson 1652e97ad33aSDoug Rabson if ((cnp->cn_flags & MAKEENTRY) != 0) { 1653e97ad33aSDoug Rabson cache_enter(P9FS_NTOV(dnp), *vpp, cnp); 1654e97ad33aSDoug Rabson } 1655e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: created file under vp %p node %p fid %ju\n", 1656e97ad33aSDoug Rabson __func__, *vpp, dnp, (uintmax_t)dvfid->fid); 1657e97ad33aSDoug Rabson 1658e97ad33aSDoug Rabson cnp->cn_nameptr[cnp->cn_namelen] = tmpchr; 1659e97ad33aSDoug Rabson return (error); 1660e97ad33aSDoug Rabson 1661e97ad33aSDoug Rabson out: 1662e97ad33aSDoug Rabson if (newfid != NULL) 1663e97ad33aSDoug Rabson p9_client_clunk(newfid); 1664e97ad33aSDoug Rabson cnp->cn_nameptr[cnp->cn_namelen] = tmpchr; 1665e97ad33aSDoug Rabson return (error); 1666e97ad33aSDoug Rabson } 1667e97ad33aSDoug Rabson 1668e97ad33aSDoug Rabson /* Create hard link */ 1669e97ad33aSDoug Rabson static int 1670e97ad33aSDoug Rabson p9fs_link(struct vop_link_args *ap) 1671e97ad33aSDoug Rabson { 1672e97ad33aSDoug Rabson struct vnode *vp; 1673e97ad33aSDoug Rabson struct vnode *tdvp; 1674e97ad33aSDoug Rabson struct componentname *cnp; 1675e97ad33aSDoug Rabson struct p9fs_node *dnp; 1676e97ad33aSDoug Rabson struct p9fs_node *np; 1677e97ad33aSDoug Rabson struct p9fs_inode *inode; 1678e97ad33aSDoug Rabson struct p9fs_session *vses; 1679e97ad33aSDoug Rabson struct p9_fid *dvfid, *oldvfid; 1680e97ad33aSDoug Rabson int error; 1681e97ad33aSDoug Rabson 1682e97ad33aSDoug Rabson vp = ap->a_vp; 1683e97ad33aSDoug Rabson tdvp = ap->a_tdvp; 1684e97ad33aSDoug Rabson cnp = ap->a_cnp; 1685e97ad33aSDoug Rabson dnp = P9FS_VTON(tdvp); 1686e97ad33aSDoug Rabson np = P9FS_VTON(vp); 1687e97ad33aSDoug Rabson inode = &np->inode; 1688e97ad33aSDoug Rabson vses = np->p9fs_ses; 1689e97ad33aSDoug Rabson error = 0; 1690e97ad33aSDoug Rabson 1691e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: tdvp %p vp %p\n", __func__, tdvp, vp); 1692e97ad33aSDoug Rabson 1693e97ad33aSDoug Rabson dvfid = p9fs_get_fid(vses->clnt, dnp, cnp->cn_cred, VFID, -1, &error); 1694e97ad33aSDoug Rabson if (error != 0) 1695e97ad33aSDoug Rabson return (error); 1696e97ad33aSDoug Rabson oldvfid = p9fs_get_fid(vses->clnt, np, cnp->cn_cred, VFID, -1, &error); 1697e97ad33aSDoug Rabson if (error != 0) 1698e97ad33aSDoug Rabson return (error); 1699e97ad33aSDoug Rabson 1700e97ad33aSDoug Rabson error = p9_create_hardlink(dvfid, oldvfid, cnp->cn_nameptr); 1701e97ad33aSDoug Rabson if (error != 0) 1702e97ad33aSDoug Rabson return (error); 1703e97ad33aSDoug Rabson /* Increment ref count on the inode */ 1704e97ad33aSDoug Rabson P9FS_INCR_LINKS(inode); 1705e97ad33aSDoug Rabson 1706e97ad33aSDoug Rabson return (0); 1707e97ad33aSDoug Rabson } 1708e97ad33aSDoug Rabson 1709e97ad33aSDoug Rabson /* Read contents of the symbolic link */ 1710e97ad33aSDoug Rabson static int 1711e97ad33aSDoug Rabson p9fs_readlink(struct vop_readlink_args *ap) 1712e97ad33aSDoug Rabson { 1713e97ad33aSDoug Rabson struct vnode *vp; 1714e97ad33aSDoug Rabson struct uio *uio; 1715e97ad33aSDoug Rabson struct p9fs_node *dnp; 1716e97ad33aSDoug Rabson struct p9fs_session *vses; 1717e97ad33aSDoug Rabson struct p9_fid *dvfid; 1718e97ad33aSDoug Rabson int error, len; 1719e97ad33aSDoug Rabson char *target; 1720e97ad33aSDoug Rabson 1721e97ad33aSDoug Rabson vp = ap->a_vp; 1722e97ad33aSDoug Rabson uio = ap->a_uio; 1723e97ad33aSDoug Rabson dnp = P9FS_VTON(vp); 1724e97ad33aSDoug Rabson vses = dnp->p9fs_ses; 1725e97ad33aSDoug Rabson error = 0; 1726e97ad33aSDoug Rabson 1727e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: vp %p\n", __func__, vp); 1728e97ad33aSDoug Rabson 1729e97ad33aSDoug Rabson dvfid = p9fs_get_fid(vses->clnt, dnp, ap->a_cred, VFID, -1, &error); 1730e97ad33aSDoug Rabson if (error != 0) 1731e97ad33aSDoug Rabson return (error); 1732e97ad33aSDoug Rabson 1733e97ad33aSDoug Rabson error = p9_readlink(dvfid, &target); 1734e97ad33aSDoug Rabson if (error != 0) 1735e97ad33aSDoug Rabson return (error); 1736e97ad33aSDoug Rabson 1737e97ad33aSDoug Rabson len = strlen(target); 1738e97ad33aSDoug Rabson error = uiomove(target, len, uio); 1739e97ad33aSDoug Rabson 1740e97ad33aSDoug Rabson return (0); 1741e97ad33aSDoug Rabson } 1742e97ad33aSDoug Rabson 1743e97ad33aSDoug Rabson /* 1744e97ad33aSDoug Rabson * Iterate through a directory. An entire 8k data is read into the I/O buffer. 1745e97ad33aSDoug Rabson * This buffer is parsed to make dir entries and fed to the user buffer to 1746e97ad33aSDoug Rabson * complete it to the VFS. 1747e97ad33aSDoug Rabson */ 1748e97ad33aSDoug Rabson static int 1749e97ad33aSDoug Rabson p9fs_readdir(struct vop_readdir_args *ap) 1750e97ad33aSDoug Rabson { 1751e97ad33aSDoug Rabson struct uio *uio; 1752e97ad33aSDoug Rabson struct vnode *vp; 1753e97ad33aSDoug Rabson struct dirent cde; 1754e97ad33aSDoug Rabson int64_t offset; 1755e97ad33aSDoug Rabson uint64_t diroffset; 1756e97ad33aSDoug Rabson struct p9fs_node *np; 1757e97ad33aSDoug Rabson int error; 1758e97ad33aSDoug Rabson int32_t count; 1759e97ad33aSDoug Rabson struct p9_client *clnt; 1760e97ad33aSDoug Rabson struct p9_dirent dent; 1761e97ad33aSDoug Rabson char *io_buffer; 1762e97ad33aSDoug Rabson struct p9_fid *vofid; 1763e97ad33aSDoug Rabson 1764e97ad33aSDoug Rabson uio = ap->a_uio; 1765e97ad33aSDoug Rabson vp = ap->a_vp; 1766e97ad33aSDoug Rabson np = P9FS_VTON(ap->a_vp); 1767e97ad33aSDoug Rabson offset = 0; 1768e97ad33aSDoug Rabson diroffset = 0; 1769e97ad33aSDoug Rabson error = 0; 1770e97ad33aSDoug Rabson count = 0; 1771e97ad33aSDoug Rabson clnt = np->p9fs_ses->clnt; 1772e97ad33aSDoug Rabson 1773b2ebcd19SDoug Rabson P9_DEBUG(VOPS, "%s: vp %p, offset %jd, resid %zd\n", __func__, vp, (intmax_t) uio->uio_offset, uio->uio_resid); 1774e97ad33aSDoug Rabson 1775e97ad33aSDoug Rabson if (ap->a_uio->uio_iov->iov_len <= 0) 1776e97ad33aSDoug Rabson return (EINVAL); 1777e97ad33aSDoug Rabson 1778e97ad33aSDoug Rabson if (vp->v_type != VDIR) 1779e97ad33aSDoug Rabson return (ENOTDIR); 1780e97ad33aSDoug Rabson 1781e97ad33aSDoug Rabson vofid = p9fs_get_fid(clnt, np, ap->a_cred, VOFID, P9PROTO_OREAD, &error); 1782e97ad33aSDoug Rabson if (vofid == NULL) { 1783e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: NULL FID\n", __func__); 1784e97ad33aSDoug Rabson return (EBADF); 1785e97ad33aSDoug Rabson } 1786e97ad33aSDoug Rabson 1787e97ad33aSDoug Rabson io_buffer = uma_zalloc(p9fs_io_buffer_zone, M_WAITOK); 1788e97ad33aSDoug Rabson 1789e97ad33aSDoug Rabson /* We haven't reached the end yet. read more. */ 1790e97ad33aSDoug Rabson diroffset = uio->uio_offset; 1791e97ad33aSDoug Rabson while (uio->uio_resid >= sizeof(struct dirent)) { 1792e97ad33aSDoug Rabson /* 1793e97ad33aSDoug Rabson * We need to read more data as what is indicated by filesize because 1794e97ad33aSDoug Rabson * filesize is based on data stored in struct dirent structure but 1795e97ad33aSDoug Rabson * we read data in struct p9_dirent format which has different size. 1796e97ad33aSDoug Rabson * Hence we read max data(P9FS_IOUNIT) everytime from host, convert 1797e97ad33aSDoug Rabson * it into struct dirent structure and send it back. 1798e97ad33aSDoug Rabson */ 1799e97ad33aSDoug Rabson count = P9FS_IOUNIT; 1800e97ad33aSDoug Rabson bzero(io_buffer, P9FS_MTU); 1801e97ad33aSDoug Rabson count = p9_client_readdir(vofid, (char *)io_buffer, 1802e97ad33aSDoug Rabson diroffset, count); 1803e97ad33aSDoug Rabson 1804e97ad33aSDoug Rabson if (count == 0) 1805e97ad33aSDoug Rabson break; 1806e97ad33aSDoug Rabson 1807e97ad33aSDoug Rabson if (count < 0) { 1808e97ad33aSDoug Rabson error = EIO; 1809e97ad33aSDoug Rabson goto out; 1810e97ad33aSDoug Rabson } 1811e97ad33aSDoug Rabson 1812e97ad33aSDoug Rabson offset = 0; 1813e97ad33aSDoug Rabson while (offset + QEMU_DIRENTRY_SZ <= count) { 1814e97ad33aSDoug Rabson 1815e97ad33aSDoug Rabson /* 1816e97ad33aSDoug Rabson * Read and make sense out of the buffer in one dirent 1817e97ad33aSDoug Rabson * This is part of 9p protocol read. This reads one p9_dirent, 1818e97ad33aSDoug Rabson * appends it to dirent(FREEBSD specifc) and continues to parse the buffer. 1819e97ad33aSDoug Rabson */ 1820e97ad33aSDoug Rabson bzero(&dent, sizeof(dent)); 1821e97ad33aSDoug Rabson offset = p9_dirent_read(clnt, io_buffer, offset, count, 1822e97ad33aSDoug Rabson &dent); 1823e97ad33aSDoug Rabson if (offset < 0 || offset > count) { 1824e97ad33aSDoug Rabson error = EIO; 1825e97ad33aSDoug Rabson goto out; 1826e97ad33aSDoug Rabson } 1827e97ad33aSDoug Rabson 1828e97ad33aSDoug Rabson bzero(&cde, sizeof(cde)); 1829e97ad33aSDoug Rabson strncpy(cde.d_name, dent.d_name, dent.len); 1830e97ad33aSDoug Rabson cde.d_fileno = dent.qid.path; 1831e97ad33aSDoug Rabson cde.d_type = dent.d_type; 1832e97ad33aSDoug Rabson cde.d_namlen = dent.len; 1833e97ad33aSDoug Rabson cde.d_reclen = GENERIC_DIRSIZ(&cde); 1834e97ad33aSDoug Rabson 1835e97ad33aSDoug Rabson /* 1836e97ad33aSDoug Rabson * If there isn't enough space in the uio to return a 1837e97ad33aSDoug Rabson * whole dirent, break off read 1838e97ad33aSDoug Rabson */ 1839e97ad33aSDoug Rabson if (uio->uio_resid < GENERIC_DIRSIZ(&cde)) 1840e97ad33aSDoug Rabson break; 1841e97ad33aSDoug Rabson 1842e97ad33aSDoug Rabson /* Transfer */ 1843e97ad33aSDoug Rabson error = uiomove(&cde, GENERIC_DIRSIZ(&cde), uio); 1844e97ad33aSDoug Rabson if (error != 0) { 1845e97ad33aSDoug Rabson error = EIO; 1846e97ad33aSDoug Rabson goto out; 1847e97ad33aSDoug Rabson } 1848e97ad33aSDoug Rabson diroffset = dent.d_off; 1849e97ad33aSDoug Rabson } 1850e97ad33aSDoug Rabson } 1851e97ad33aSDoug Rabson /* Pass on last transferred offset */ 1852e97ad33aSDoug Rabson uio->uio_offset = diroffset; 1853e97ad33aSDoug Rabson 1854e97ad33aSDoug Rabson out: 1855e97ad33aSDoug Rabson uma_zfree(p9fs_io_buffer_zone, io_buffer); 1856e97ad33aSDoug Rabson 1857e97ad33aSDoug Rabson return (error); 1858e97ad33aSDoug Rabson } 1859e97ad33aSDoug Rabson 1860e97ad33aSDoug Rabson static void 1861e97ad33aSDoug Rabson p9fs_doio(struct vnode *vp, struct buf *bp, struct p9_fid *vofid, struct ucred *cr) 1862e97ad33aSDoug Rabson { 1863e97ad33aSDoug Rabson struct uio *uiov; 1864e97ad33aSDoug Rabson struct iovec io; 1865e97ad33aSDoug Rabson int error; 1866e97ad33aSDoug Rabson uint64_t off, offset; 1867e97ad33aSDoug Rabson uint64_t filesize; 1868e97ad33aSDoug Rabson uint64_t resid; 1869e97ad33aSDoug Rabson uint32_t count; 1870e97ad33aSDoug Rabson int64_t ret; 1871e97ad33aSDoug Rabson struct p9fs_node *np; 1872e97ad33aSDoug Rabson char *io_buffer; 1873e97ad33aSDoug Rabson 1874e97ad33aSDoug Rabson error = 0; 1875e97ad33aSDoug Rabson np = P9FS_VTON(vp); 1876e97ad33aSDoug Rabson 1877e97ad33aSDoug Rabson filesize = np->inode.i_size; 1878e97ad33aSDoug Rabson uiov = malloc(sizeof(struct uio), M_P9UIOV, M_WAITOK); 1879e97ad33aSDoug Rabson uiov->uio_iov = &io; 1880e97ad33aSDoug Rabson uiov->uio_iovcnt = 1; 1881e97ad33aSDoug Rabson uiov->uio_segflg = UIO_SYSSPACE; 1882e97ad33aSDoug Rabson io_buffer = uma_zalloc(p9fs_io_buffer_zone, M_WAITOK | M_ZERO); 1883e97ad33aSDoug Rabson 1884e97ad33aSDoug Rabson if (bp->b_iocmd == BIO_READ) { 1885e97ad33aSDoug Rabson io.iov_len = uiov->uio_resid = bp->b_bcount; 1886e97ad33aSDoug Rabson io.iov_base = bp->b_data; 1887e97ad33aSDoug Rabson uiov->uio_rw = UIO_READ; 1888e97ad33aSDoug Rabson 1889e97ad33aSDoug Rabson switch (vp->v_type) { 1890e97ad33aSDoug Rabson 1891e97ad33aSDoug Rabson case VREG: 1892e97ad33aSDoug Rabson { 1893e97ad33aSDoug Rabson uiov->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE; 1894e97ad33aSDoug Rabson 1895e97ad33aSDoug Rabson if (uiov->uio_resid) { 1896e97ad33aSDoug Rabson int left = uiov->uio_resid; 1897e97ad33aSDoug Rabson int nread = bp->b_bcount - left; 1898e97ad33aSDoug Rabson 1899e97ad33aSDoug Rabson if (left > 0) 1900e97ad33aSDoug Rabson bzero((char *)bp->b_data + nread, left); 1901e97ad33aSDoug Rabson } 1902e97ad33aSDoug Rabson /* where in the file are we to start reading */ 1903e97ad33aSDoug Rabson offset = uiov->uio_offset; 1904e97ad33aSDoug Rabson if (uiov->uio_offset >= filesize) 1905e97ad33aSDoug Rabson goto out; 1906e97ad33aSDoug Rabson 1907e97ad33aSDoug Rabson while ((resid = uiov->uio_resid) > 0) { 1908e97ad33aSDoug Rabson if (offset >= filesize) 1909e97ad33aSDoug Rabson break; 1910e97ad33aSDoug Rabson count = min(filesize - uiov->uio_offset, resid); 1911e97ad33aSDoug Rabson if (count == 0) 1912e97ad33aSDoug Rabson break; 1913e97ad33aSDoug Rabson 1914e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: read called %#zx at %#jx\n", 1915e97ad33aSDoug Rabson __func__, uiov->uio_resid, (uintmax_t)uiov->uio_offset); 1916e97ad33aSDoug Rabson 1917e97ad33aSDoug Rabson /* Copy count bytes into the uio */ 1918e97ad33aSDoug Rabson ret = p9_client_read(vofid, offset, count, io_buffer); 1919e97ad33aSDoug Rabson error = uiomove(io_buffer, ret, uiov); 1920e97ad33aSDoug Rabson 1921e97ad33aSDoug Rabson if (error != 0) 1922e97ad33aSDoug Rabson goto out; 1923e97ad33aSDoug Rabson offset += ret; 1924e97ad33aSDoug Rabson } 1925e97ad33aSDoug Rabson break; 1926e97ad33aSDoug Rabson } 1927e97ad33aSDoug Rabson default: 1928e97ad33aSDoug Rabson printf("vfs: type %x unexpected\n", vp->v_type); 1929e97ad33aSDoug Rabson break; 1930e97ad33aSDoug Rabson } 1931e97ad33aSDoug Rabson } else { 1932e97ad33aSDoug Rabson if (bp->b_dirtyend > bp->b_dirtyoff) { 1933e97ad33aSDoug Rabson io.iov_len = uiov->uio_resid = bp->b_dirtyend - bp->b_dirtyoff; 1934e97ad33aSDoug Rabson uiov->uio_offset = ((off_t)bp->b_blkno) * PAGE_SIZE + bp->b_dirtyoff; 1935e97ad33aSDoug Rabson io.iov_base = (char *)bp->b_data + bp->b_dirtyoff; 1936e97ad33aSDoug Rabson uiov->uio_rw = UIO_WRITE; 1937e97ad33aSDoug Rabson 1938e97ad33aSDoug Rabson if (uiov->uio_offset < 0) { 1939e97ad33aSDoug Rabson error = EINVAL; 1940e97ad33aSDoug Rabson goto out; 1941e97ad33aSDoug Rabson } 1942e97ad33aSDoug Rabson 1943e97ad33aSDoug Rabson if (uiov->uio_resid == 0) 1944e97ad33aSDoug Rabson goto out; 1945e97ad33aSDoug Rabson 1946e97ad33aSDoug Rabson resid = uiov->uio_resid; 1947e97ad33aSDoug Rabson offset = uiov->uio_offset; 1948e97ad33aSDoug Rabson error = 0; 1949e97ad33aSDoug Rabson 1950e97ad33aSDoug Rabson while ((resid = uiov->uio_resid) > 0) { 1951e97ad33aSDoug Rabson off = 0; 1952e97ad33aSDoug Rabson count = MIN(resid, P9FS_IOUNIT); 1953e97ad33aSDoug Rabson error = uiomove(io_buffer, count, uiov); 1954e97ad33aSDoug Rabson if (error != 0) { 1955e97ad33aSDoug Rabson goto out; 1956e97ad33aSDoug Rabson } 1957e97ad33aSDoug Rabson 1958e97ad33aSDoug Rabson while (count > 0) { 1959e97ad33aSDoug Rabson /* Copy count bytes from the uio */ 1960e97ad33aSDoug Rabson ret = p9_client_write(vofid, offset, count, 1961e97ad33aSDoug Rabson io_buffer + off); 1962e97ad33aSDoug Rabson if (ret < 0) 1963e97ad33aSDoug Rabson goto out; 1964e97ad33aSDoug Rabson 1965e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: write called %#zx at %#jx\n", 1966e97ad33aSDoug Rabson __func__, uiov->uio_resid, (uintmax_t)uiov->uio_offset); 1967e97ad33aSDoug Rabson off += ret; 1968e97ad33aSDoug Rabson offset += ret; 1969e97ad33aSDoug Rabson count -= ret; 1970e97ad33aSDoug Rabson } 1971e97ad33aSDoug Rabson } 1972e97ad33aSDoug Rabson 1973e97ad33aSDoug Rabson /* Update the fields in the node to reflect the change */ 1974e97ad33aSDoug Rabson if (filesize < uiov->uio_offset + uiov->uio_resid) { 1975e97ad33aSDoug Rabson np->inode.i_size = uiov->uio_offset + uiov->uio_resid; 1976e97ad33aSDoug Rabson vnode_pager_setsize(vp, uiov->uio_offset + uiov->uio_resid); 1977e97ad33aSDoug Rabson /* update the modified timers. */ 1978e97ad33aSDoug Rabson p9fs_itimes(vp); 1979e97ad33aSDoug Rabson } 1980e97ad33aSDoug Rabson } else { 1981e97ad33aSDoug Rabson bp->b_resid = 0; 1982e97ad33aSDoug Rabson goto out1; 1983e97ad33aSDoug Rabson } 1984e97ad33aSDoug Rabson } 1985e97ad33aSDoug Rabson out: 1986e97ad33aSDoug Rabson /* Set the error */ 1987e97ad33aSDoug Rabson if (error != 0) { 1988e97ad33aSDoug Rabson bp->b_error = error; 1989e97ad33aSDoug Rabson bp->b_ioflags |= BIO_ERROR; 1990e97ad33aSDoug Rabson } 1991e97ad33aSDoug Rabson bp->b_resid = uiov->uio_resid; 1992e97ad33aSDoug Rabson out1: 1993e97ad33aSDoug Rabson bufdone(bp); 1994e97ad33aSDoug Rabson uma_zfree(p9fs_io_buffer_zone, io_buffer); 1995e97ad33aSDoug Rabson free(uiov, M_P9UIOV); 1996e97ad33aSDoug Rabson } 1997e97ad33aSDoug Rabson 1998e97ad33aSDoug Rabson /* 1999e97ad33aSDoug Rabson * The I/O buffer is mapped to a uio and a client_write/client_read is performed 2000e97ad33aSDoug Rabson * the same way as p9fs_read and p9fs_write. 2001e97ad33aSDoug Rabson */ 2002e97ad33aSDoug Rabson static int 2003e97ad33aSDoug Rabson p9fs_strategy(struct vop_strategy_args *ap) 2004e97ad33aSDoug Rabson { 2005e97ad33aSDoug Rabson struct vnode *vp; 2006e97ad33aSDoug Rabson struct buf *bp; 2007e97ad33aSDoug Rabson struct ucred *cr; 2008e97ad33aSDoug Rabson int error; 2009e97ad33aSDoug Rabson struct open_fid_state ostate; 2010e97ad33aSDoug Rabson 2011e97ad33aSDoug Rabson vp = ap->a_vp; 2012e97ad33aSDoug Rabson bp = ap->a_bp; 2013e97ad33aSDoug Rabson error = 0; 2014e97ad33aSDoug Rabson 2015e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: vp %p, iocmd %d\n ", __func__, vp, bp->b_iocmd); 2016e97ad33aSDoug Rabson 2017e97ad33aSDoug Rabson if (bp->b_iocmd == BIO_READ) 2018e97ad33aSDoug Rabson cr = bp->b_rcred; 2019e97ad33aSDoug Rabson else 2020e97ad33aSDoug Rabson cr = bp->b_wcred; 2021e97ad33aSDoug Rabson 2022e97ad33aSDoug Rabson error = p9fs_get_open_fid(vp, bp->b_iocmd == BIO_READ ? FREAD : FWRITE, cr, &ostate); 2023e97ad33aSDoug Rabson if (error) { 2024e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: p9fs_get_open_fid failed: %d\n", __func__, error); 2025e97ad33aSDoug Rabson bp->b_error = error; 2026e97ad33aSDoug Rabson bp->b_ioflags |= BIO_ERROR; 2027e97ad33aSDoug Rabson bufdone(bp); 2028e97ad33aSDoug Rabson return (0); 2029e97ad33aSDoug Rabson } 2030e97ad33aSDoug Rabson 2031e97ad33aSDoug Rabson p9fs_doio(vp, bp, ostate.vofid, cr); 2032e97ad33aSDoug Rabson p9fs_release_open_fid(vp, cr, &ostate); 2033e97ad33aSDoug Rabson 2034e97ad33aSDoug Rabson return (0); 2035e97ad33aSDoug Rabson } 2036e97ad33aSDoug Rabson 2037e97ad33aSDoug Rabson /* Rename a file */ 2038e97ad33aSDoug Rabson static int 2039e97ad33aSDoug Rabson p9fs_rename(struct vop_rename_args *ap) 2040e97ad33aSDoug Rabson { 2041e97ad33aSDoug Rabson struct vnode *tvp; 2042e97ad33aSDoug Rabson struct vnode *tdvp; 2043e97ad33aSDoug Rabson struct vnode *fvp; 2044e97ad33aSDoug Rabson struct vnode *fdvp; 2045e97ad33aSDoug Rabson struct componentname *tcnp; 2046e97ad33aSDoug Rabson struct componentname *fcnp; 2047e97ad33aSDoug Rabson struct p9fs_node *tdnode; 2048e97ad33aSDoug Rabson struct p9fs_node *fdnode; 2049e97ad33aSDoug Rabson struct p9fs_inode *fdinode; 2050e97ad33aSDoug Rabson struct p9fs_node *fnode; 2051e97ad33aSDoug Rabson struct p9fs_inode *finode; 2052e97ad33aSDoug Rabson struct p9fs_session *vses; 2053e97ad33aSDoug Rabson struct p9fs_node *tnode; 2054e97ad33aSDoug Rabson struct p9fs_inode *tinode; 2055e97ad33aSDoug Rabson struct p9_fid *olddirvfid, *newdirvfid ; 2056e97ad33aSDoug Rabson int error; 2057e97ad33aSDoug Rabson 2058e97ad33aSDoug Rabson tvp = ap->a_tvp; 2059e97ad33aSDoug Rabson tdvp = ap->a_tdvp; 2060e97ad33aSDoug Rabson fvp = ap->a_fvp; 2061e97ad33aSDoug Rabson fdvp = ap->a_fdvp; 2062e97ad33aSDoug Rabson tcnp = ap->a_tcnp; 2063e97ad33aSDoug Rabson fcnp = ap->a_fcnp; 2064e97ad33aSDoug Rabson tdnode = P9FS_VTON(tdvp); 2065e97ad33aSDoug Rabson fdnode = P9FS_VTON(fdvp); 2066e97ad33aSDoug Rabson fdinode = &fdnode->inode; 2067e97ad33aSDoug Rabson fnode = P9FS_VTON(fvp); 2068e97ad33aSDoug Rabson finode = &fnode->inode; 2069e97ad33aSDoug Rabson vses = fnode->p9fs_ses; 2070e97ad33aSDoug Rabson error = 0; 2071e97ad33aSDoug Rabson 2072e97ad33aSDoug Rabson P9_DEBUG(VOPS, "%s: tvp %p, tdvp %p, fvp %p, fdvp %p\n ", __func__, tvp, tdvp, fvp, fdvp); 2073e97ad33aSDoug Rabson 2074e97ad33aSDoug Rabson /* Check for cross mount operation */ 2075e97ad33aSDoug Rabson if (fvp->v_mount != tdvp->v_mount || 2076e97ad33aSDoug Rabson (tvp && (fvp->v_mount != tvp->v_mount))) { 2077e97ad33aSDoug Rabson error = EXDEV; 2078e97ad33aSDoug Rabson goto out; 2079e97ad33aSDoug Rabson } 2080e97ad33aSDoug Rabson 2081e97ad33aSDoug Rabson /* warning if you are renaming to the same name */ 2082e97ad33aSDoug Rabson if (fvp == tvp) 2083e97ad33aSDoug Rabson error = 0; 2084e97ad33aSDoug Rabson 2085e97ad33aSDoug Rabson olddirvfid = p9fs_get_fid(vses->clnt, fdnode, fcnp->cn_cred, VFID, -1, &error); 2086e97ad33aSDoug Rabson if (error != 0) 2087e97ad33aSDoug Rabson goto out; 2088e97ad33aSDoug Rabson newdirvfid = p9fs_get_fid(vses->clnt, tdnode, tcnp->cn_cred, VFID, -1, &error); 2089e97ad33aSDoug Rabson if (error != 0) 2090e97ad33aSDoug Rabson goto out; 2091e97ad33aSDoug Rabson 2092e97ad33aSDoug Rabson error = p9_client_renameat(olddirvfid, fcnp->cn_nameptr, newdirvfid, tcnp->cn_nameptr); 2093e97ad33aSDoug Rabson if (error != 0) 2094e97ad33aSDoug Rabson goto out; 2095e97ad33aSDoug Rabson 2096e97ad33aSDoug Rabson /* 2097e97ad33aSDoug Rabson * decrement the link count on the "from" file whose name is going 2098e97ad33aSDoug Rabson * to be changed if its a directory 2099e97ad33aSDoug Rabson */ 2100e97ad33aSDoug Rabson if (fvp->v_type == VDIR) { 2101e97ad33aSDoug Rabson if (tvp && tvp->v_type == VDIR) 2102e97ad33aSDoug Rabson cache_purge(tdvp); 2103e97ad33aSDoug Rabson P9FS_DECR_LINKS(fdinode); 2104e97ad33aSDoug Rabson cache_purge(fdvp); 2105e97ad33aSDoug Rabson } 2106e97ad33aSDoug Rabson 2107e97ad33aSDoug Rabson /* Taking exclusive lock on the from node before decrementing the link count */ 2108e97ad33aSDoug Rabson if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0) 2109e97ad33aSDoug Rabson goto out; 2110e97ad33aSDoug Rabson P9FS_DECR_LINKS(finode); 2111e97ad33aSDoug Rabson VOP_UNLOCK(fvp); 2112e97ad33aSDoug Rabson 2113e97ad33aSDoug Rabson if (tvp) { 2114e97ad33aSDoug Rabson tnode = P9FS_VTON(tvp); 2115e97ad33aSDoug Rabson tinode = &tnode->inode; 2116e97ad33aSDoug Rabson P9FS_DECR_LINKS(tinode); 2117e97ad33aSDoug Rabson } 2118e97ad33aSDoug Rabson 2119e97ad33aSDoug Rabson out: 2120e97ad33aSDoug Rabson if (tdvp == tvp) 2121e97ad33aSDoug Rabson vrele(tdvp); 2122e97ad33aSDoug Rabson else 2123e97ad33aSDoug Rabson vput(tdvp); 2124e97ad33aSDoug Rabson if (tvp) 2125e97ad33aSDoug Rabson vput(tvp); 2126e97ad33aSDoug Rabson vrele(fdvp); 2127e97ad33aSDoug Rabson vrele(fvp); 2128e97ad33aSDoug Rabson return (error); 2129e97ad33aSDoug Rabson } 2130e97ad33aSDoug Rabson 2131daa2c99cSVal Packett /* 2132daa2c99cSVal Packett * Put VM pages, synchronously. 2133daa2c99cSVal Packett * XXX: like smbfs, cannot use vop_stdputpages due to mapping requirement 2134daa2c99cSVal Packett */ 2135daa2c99cSVal Packett static int 2136daa2c99cSVal Packett p9fs_putpages(struct vop_putpages_args *ap) 2137daa2c99cSVal Packett { 2138daa2c99cSVal Packett struct uio uio; 2139daa2c99cSVal Packett struct iovec iov; 2140daa2c99cSVal Packett int i, error, npages, count; 2141daa2c99cSVal Packett off_t offset; 2142daa2c99cSVal Packett int *rtvals; 2143daa2c99cSVal Packett struct vnode *vp; 2144daa2c99cSVal Packett struct thread *td; 2145daa2c99cSVal Packett struct ucred *cred; 2146daa2c99cSVal Packett struct p9fs_node *np; 2147daa2c99cSVal Packett vm_page_t *pages; 2148daa2c99cSVal Packett vm_offset_t kva; 2149daa2c99cSVal Packett struct buf *bp; 2150daa2c99cSVal Packett 2151daa2c99cSVal Packett vp = ap->a_vp; 2152daa2c99cSVal Packett np = P9FS_VTON(vp); 2153daa2c99cSVal Packett td = curthread; 2154daa2c99cSVal Packett cred = curthread->td_ucred; 2155daa2c99cSVal Packett pages = ap->a_m; 2156daa2c99cSVal Packett count = ap->a_count; 2157daa2c99cSVal Packett rtvals = ap->a_rtvals; 2158daa2c99cSVal Packett npages = btoc(count); 2159daa2c99cSVal Packett offset = IDX_TO_OFF(pages[0]->pindex); 2160daa2c99cSVal Packett 2161daa2c99cSVal Packett /* 2162daa2c99cSVal Packett * When putting pages, do not extend file past EOF. 2163daa2c99cSVal Packett */ 2164daa2c99cSVal Packett if (offset + count > np->inode.i_size) { 2165daa2c99cSVal Packett count = np->inode.i_size - offset; 2166daa2c99cSVal Packett if (count < 0) 2167daa2c99cSVal Packett count = 0; 2168daa2c99cSVal Packett } 2169daa2c99cSVal Packett 2170daa2c99cSVal Packett for (i = 0; i < npages; i++) 2171daa2c99cSVal Packett rtvals[i] = VM_PAGER_ERROR; 2172daa2c99cSVal Packett 2173daa2c99cSVal Packett bp = uma_zalloc(p9fs_pbuf_zone, M_WAITOK); 2174daa2c99cSVal Packett kva = (vm_offset_t) bp->b_data; 2175daa2c99cSVal Packett pmap_qenter(kva, pages, npages); 2176daa2c99cSVal Packett 2177daa2c99cSVal Packett VM_CNT_INC(v_vnodeout); 2178daa2c99cSVal Packett VM_CNT_ADD(v_vnodepgsout, count); 2179daa2c99cSVal Packett 2180daa2c99cSVal Packett iov.iov_base = (caddr_t) kva; 2181daa2c99cSVal Packett iov.iov_len = count; 2182daa2c99cSVal Packett uio.uio_iov = &iov; 2183daa2c99cSVal Packett uio.uio_iovcnt = 1; 2184daa2c99cSVal Packett uio.uio_offset = offset; 2185daa2c99cSVal Packett uio.uio_resid = count; 2186daa2c99cSVal Packett uio.uio_segflg = UIO_SYSSPACE; 2187daa2c99cSVal Packett uio.uio_rw = UIO_WRITE; 2188daa2c99cSVal Packett uio.uio_td = td; 2189daa2c99cSVal Packett 2190daa2c99cSVal Packett P9_DEBUG(VOPS, "of=%jd,resid=%zd\n", (intmax_t)uio.uio_offset, uio.uio_resid); 2191daa2c99cSVal Packett 2192daa2c99cSVal Packett error = VOP_WRITE(vp, &uio, vnode_pager_putpages_ioflags(ap->a_sync), 2193daa2c99cSVal Packett cred); 2194daa2c99cSVal Packett 2195daa2c99cSVal Packett pmap_qremove(kva, npages); 2196daa2c99cSVal Packett uma_zfree(p9fs_pbuf_zone, bp); 2197daa2c99cSVal Packett 2198daa2c99cSVal Packett if (error == 0) 2199daa2c99cSVal Packett vnode_pager_undirty_pages(pages, rtvals, count - uio.uio_resid, 2200daa2c99cSVal Packett np->inode.i_size - offset, npages * PAGE_SIZE); 2201daa2c99cSVal Packett 2202daa2c99cSVal Packett return (rtvals[0]); 2203daa2c99cSVal Packett } 2204e97ad33aSDoug Rabson 2205e97ad33aSDoug Rabson struct vop_vector p9fs_vnops = { 2206e97ad33aSDoug Rabson .vop_default = &default_vnodeops, 2207e97ad33aSDoug Rabson .vop_lookup = p9fs_lookup, 2208e97ad33aSDoug Rabson .vop_open = p9fs_open, 2209e97ad33aSDoug Rabson .vop_close = p9fs_close, 2210e97ad33aSDoug Rabson .vop_access = p9fs_access, 2211e97ad33aSDoug Rabson .vop_getattr = p9fs_getattr_dotl, 2212e97ad33aSDoug Rabson .vop_setattr = p9fs_setattr_dotl, 2213e97ad33aSDoug Rabson .vop_reclaim = p9fs_reclaim, 2214e97ad33aSDoug Rabson .vop_inactive = p9fs_inactive, 2215e97ad33aSDoug Rabson .vop_readdir = p9fs_readdir, 2216e97ad33aSDoug Rabson .vop_create = p9fs_create, 2217e97ad33aSDoug Rabson .vop_mknod = p9fs_mknod, 2218e97ad33aSDoug Rabson .vop_read = p9fs_read, 2219e97ad33aSDoug Rabson .vop_write = p9fs_write, 2220e97ad33aSDoug Rabson .vop_remove = p9fs_remove, 2221e97ad33aSDoug Rabson .vop_mkdir = p9fs_mkdir, 2222e97ad33aSDoug Rabson .vop_rmdir = p9fs_rmdir, 2223e97ad33aSDoug Rabson .vop_strategy = p9fs_strategy, 2224e97ad33aSDoug Rabson .vop_symlink = p9fs_symlink, 2225e97ad33aSDoug Rabson .vop_rename = p9fs_rename, 2226e97ad33aSDoug Rabson .vop_link = p9fs_link, 2227e97ad33aSDoug Rabson .vop_readlink = p9fs_readlink, 2228daa2c99cSVal Packett .vop_putpages = p9fs_putpages, 2229e97ad33aSDoug Rabson }; 2230e97ad33aSDoug Rabson VFS_VOP_VECTOR_REGISTER(p9fs_vnops); 2231