zfs_vnops.c revision 212694
1174294Sobrien/* 2131702Smbr * CDDL HEADER START 3174294Sobrien * 4174294Sobrien * The contents of this file are subject to the terms of the 5174294Sobrien * Common Development and Distribution License (the "License"). 6131702Smbr * You may not use this file except in compliance with the License. 7174294Sobrien * 8131702Smbr * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9174294Sobrien * or http://www.opensolaris.org/os/licensing. 10174294Sobrien * See the License for the specific language governing permissions 11131702Smbr * and limitations under the License. 12174294Sobrien * 13174294Sobrien * When distributing Covered Code, include this CDDL HEADER in each 14131702Smbr * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15174294Sobrien * If applicable, add the following below this CDDL HEADER, with the 16174294Sobrien * fields enclosed by brackets "[]" replaced with your own identifying 17131702Smbr * information: Portions Copyright [yyyy] [name of copyright owner] 18174294Sobrien * 19131702Smbr * CDDL HEADER END 20174294Sobrien */ 21174294Sobrien/* 22174294Sobrien * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23131702Smbr */ 24174294Sobrien 25131702Smbr/* Portions Copyright 2007 Jeremy Teo */ 26174294Sobrien 27174294Sobrien#include <sys/types.h> 28174294Sobrien#include <sys/param.h> 29174294Sobrien#include <sys/time.h> 30174294Sobrien#include <sys/systm.h> 31174294Sobrien#include <sys/sysmacros.h> 32174294Sobrien#include <sys/resource.h> 33174294Sobrien#include <sys/vfs.h> 34174294Sobrien#include <sys/vnode.h> 35174294Sobrien#include <sys/file.h> 36174294Sobrien#include <sys/stat.h> 37174294Sobrien#include <sys/kmem.h> 38174294Sobrien#include <sys/taskq.h> 39174294Sobrien#include <sys/uio.h> 40174294Sobrien#include <sys/atomic.h> 41174294Sobrien#include <sys/namei.h> 42174294Sobrien#include <sys/mman.h> 43174294Sobrien#include <sys/cmn_err.h> 44174294Sobrien#include <sys/errno.h> 45174294Sobrien#include <sys/unistd.h> 46174294Sobrien#include <sys/zfs_dir.h> 47174294Sobrien#include <sys/zfs_ioctl.h> 48174294Sobrien#include <sys/fs/zfs.h> 49174294Sobrien#include <sys/dmu.h> 50174294Sobrien#include <sys/spa.h> 51174294Sobrien#include <sys/txg.h> 52174294Sobrien#include <sys/dbuf.h> 53174294Sobrien#include <sys/zap.h> 54174294Sobrien#include <sys/dirent.h> 55174294Sobrien#include <sys/policy.h> 56174294Sobrien#include <sys/sunddi.h> 57174294Sobrien#include <sys/filio.h> 58174294Sobrien#include <sys/sid.h> 59174294Sobrien#include <sys/zfs_ctldir.h> 60174294Sobrien#include <sys/zfs_fuid.h> 61174294Sobrien#include <sys/dnlc.h> 62174294Sobrien#include <sys/zfs_rlock.h> 63174294Sobrien#include <sys/extdirent.h> 64174294Sobrien#include <sys/kidmap.h> 65174294Sobrien#include <sys/bio.h> 66174294Sobrien#include <sys/buf.h> 67174294Sobrien#include <sys/sf_buf.h> 68174294Sobrien#include <sys/sched.h> 69174294Sobrien#include <sys/acl.h> 70174294Sobrien 71174294Sobrien/* 72174294Sobrien * Programming rules. 73174294Sobrien * 74174294Sobrien * Each vnode op performs some logical unit of work. To do this, the ZPL must 75174294Sobrien * properly lock its in-core state, create a DMU transaction, do the work, 76174294Sobrien * record this work in the intent log (ZIL), commit the DMU transaction, 77174294Sobrien * and wait for the intent log to commit if it is a synchronous operation. 78174294Sobrien * Moreover, the vnode ops must work in both normal and log replay context. 79174294Sobrien * The ordering of events is important to avoid deadlocks and references 80174294Sobrien * to freed memory. The example below illustrates the following Big Rules: 81174294Sobrien * 82174294Sobrien * (1) A check must be made in each zfs thread for a mounted file system. 83174294Sobrien * This is done avoiding races using ZFS_ENTER(zfsvfs). 84174294Sobrien * A ZFS_EXIT(zfsvfs) is needed before all returns. Any znodes 85174294Sobrien * must be checked with ZFS_VERIFY_ZP(zp). Both of these macros 86174294Sobrien * can return EIO from the calling function. 87174294Sobrien * 88174294Sobrien * (2) VN_RELE() should always be the last thing except for zil_commit() 89174294Sobrien * (if necessary) and ZFS_EXIT(). This is for 3 reasons: 90174294Sobrien * First, if it's the last reference, the vnode/znode 91174294Sobrien * can be freed, so the zp may point to freed memory. Second, the last 92174294Sobrien * reference will call zfs_zinactive(), which may induce a lot of work -- 93174294Sobrien * pushing cached pages (which acquires range locks) and syncing out 94174294Sobrien * cached atime changes. Third, zfs_zinactive() may require a new tx, 95174294Sobrien * which could deadlock the system if you were already holding one. 96174294Sobrien * If you must call VN_RELE() within a tx then use VN_RELE_ASYNC(). 97174294Sobrien * 98174294Sobrien * (3) All range locks must be grabbed before calling dmu_tx_assign(), 99174294Sobrien * as they can span dmu_tx_assign() calls. 100174294Sobrien * 101174294Sobrien * (4) Always pass TXG_NOWAIT as the second argument to dmu_tx_assign(). 102174294Sobrien * This is critical because we don't want to block while holding locks. 103174294Sobrien * Note, in particular, that if a lock is sometimes acquired before 104174294Sobrien * the tx assigns, and sometimes after (e.g. z_lock), then failing to 105174294Sobrien * use a non-blocking assign can deadlock the system. The scenario: 106174294Sobrien * 107174294Sobrien * Thread A has grabbed a lock before calling dmu_tx_assign(). 108174294Sobrien * Thread B is in an already-assigned tx, and blocks for this lock. 109174294Sobrien * Thread A calls dmu_tx_assign(TXG_WAIT) and blocks in txg_wait_open() 110174294Sobrien * forever, because the previous txg can't quiesce until B's tx commits. 111174294Sobrien * 112174294Sobrien * If dmu_tx_assign() returns ERESTART and zfsvfs->z_assign is TXG_NOWAIT, 113174294Sobrien * then drop all locks, call dmu_tx_wait(), and try again. 114174294Sobrien * 115174294Sobrien * (5) If the operation succeeded, generate the intent log entry for it 116174294Sobrien * before dropping locks. This ensures that the ordering of events 117174294Sobrien * in the intent log matches the order in which they actually occurred. 118174294Sobrien * During ZIL replay the zfs_log_* functions will update the sequence 119174294Sobrien * number to indicate the zil transaction has replayed. 120174294Sobrien * 121174294Sobrien * (6) At the end of each vnode op, the DMU tx must always commit, 122174294Sobrien * regardless of whether there were any errors. 123174294Sobrien * 124174294Sobrien * (7) After dropping all locks, invoke zil_commit(zilog, seq, foid) 125174294Sobrien * to ensure that synchronous semantics are provided when necessary. 126174294Sobrien * 127174294Sobrien * In general, this is how things should be ordered in each vnode op: 128174294Sobrien * 129174294Sobrien * ZFS_ENTER(zfsvfs); // exit if unmounted 130174294Sobrien * top: 131174294Sobrien * zfs_dirent_lock(&dl, ...) // lock directory entry (may VN_HOLD()) 132174294Sobrien * rw_enter(...); // grab any other locks you need 133174294Sobrien * tx = dmu_tx_create(...); // get DMU tx 134174294Sobrien * dmu_tx_hold_*(); // hold each object you might modify 135174294Sobrien * error = dmu_tx_assign(tx, TXG_NOWAIT); // try to assign 136174294Sobrien * if (error) { 137174294Sobrien * rw_exit(...); // drop locks 138174294Sobrien * zfs_dirent_unlock(dl); // unlock directory entry 139174294Sobrien * VN_RELE(...); // release held vnodes 140174294Sobrien * if (error == ERESTART) { 141174294Sobrien * dmu_tx_wait(tx); 142174294Sobrien * dmu_tx_abort(tx); 143174294Sobrien * goto top; 144174294Sobrien * } 145174294Sobrien * dmu_tx_abort(tx); // abort DMU tx 146174294Sobrien * ZFS_EXIT(zfsvfs); // finished in zfs 147174294Sobrien * return (error); // really out of space 148174294Sobrien * } 149174294Sobrien * error = do_real_work(); // do whatever this VOP does 150174294Sobrien * if (error == 0) 151174294Sobrien * zfs_log_*(...); // on success, make ZIL entry 152174294Sobrien * dmu_tx_commit(tx); // commit DMU tx -- error or not 153174294Sobrien * rw_exit(...); // drop locks 154174294Sobrien * zfs_dirent_unlock(dl); // unlock directory entry 155174294Sobrien * VN_RELE(...); // release held vnodes 156174294Sobrien * zil_commit(zilog, seq, foid); // synchronous when necessary 157174294Sobrien * ZFS_EXIT(zfsvfs); // finished in zfs 158174294Sobrien * return (error); // done, report error 159174294Sobrien */ 160174294Sobrien 161174294Sobrien/* ARGSUSED */ 162174294Sobrienstatic int 163174294Sobrienzfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct) 164174294Sobrien{ 165174294Sobrien znode_t *zp = VTOZ(*vpp); 166174294Sobrien zfsvfs_t *zfsvfs = zp->z_zfsvfs; 167174294Sobrien 168174294Sobrien ZFS_ENTER(zfsvfs); 169174294Sobrien ZFS_VERIFY_ZP(zp); 170174294Sobrien 171174294Sobrien if ((flag & FWRITE) && (zp->z_phys->zp_flags & ZFS_APPENDONLY) && 172174294Sobrien ((flag & FAPPEND) == 0)) { 173174294Sobrien ZFS_EXIT(zfsvfs); 174174294Sobrien return (EPERM); 175174294Sobrien } 176174294Sobrien 177174294Sobrien if (!zfs_has_ctldir(zp) && zp->z_zfsvfs->z_vscan && 178174294Sobrien ZTOV(zp)->v_type == VREG && 179174294Sobrien !(zp->z_phys->zp_flags & ZFS_AV_QUARANTINED) && 180174294Sobrien zp->z_phys->zp_size > 0) { 181174294Sobrien if (fs_vscan(*vpp, cr, 0) != 0) { 182174294Sobrien ZFS_EXIT(zfsvfs); 183174294Sobrien return (EACCES); 184174294Sobrien } 185174294Sobrien } 186174294Sobrien 187174294Sobrien /* Keep a count of the synchronous opens in the znode */ 188174294Sobrien if (flag & (FSYNC | FDSYNC)) 189174294Sobrien atomic_inc_32(&zp->z_sync_cnt); 190174294Sobrien 191174294Sobrien ZFS_EXIT(zfsvfs); 192174294Sobrien return (0); 193174294Sobrien} 194174294Sobrien 195174294Sobrien/* ARGSUSED */ 196174294Sobrienstatic int 197174294Sobrienzfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr, 198174294Sobrien caller_context_t *ct) 199174294Sobrien{ 200174294Sobrien znode_t *zp = VTOZ(vp); 201174294Sobrien zfsvfs_t *zfsvfs = zp->z_zfsvfs; 202174294Sobrien 203174294Sobrien /* 204174294Sobrien * Clean up any locks held by this process on the vp. 205174294Sobrien */ 206174294Sobrien cleanlocks(vp, ddi_get_pid(), 0); 207174294Sobrien cleanshares(vp, ddi_get_pid()); 208174294Sobrien 209174294Sobrien ZFS_ENTER(zfsvfs); 210174294Sobrien ZFS_VERIFY_ZP(zp); 211174294Sobrien 212174294Sobrien /* Decrement the synchronous opens in the znode */ 213174294Sobrien if ((flag & (FSYNC | FDSYNC)) && (count == 1)) 214174294Sobrien atomic_dec_32(&zp->z_sync_cnt); 215174294Sobrien 216174294Sobrien if (!zfs_has_ctldir(zp) && zp->z_zfsvfs->z_vscan && 217174294Sobrien ZTOV(zp)->v_type == VREG && 218174294Sobrien !(zp->z_phys->zp_flags & ZFS_AV_QUARANTINED) && 219174294Sobrien zp->z_phys->zp_size > 0) 220174294Sobrien VERIFY(fs_vscan(vp, cr, 1) == 0); 221174294Sobrien 222174294Sobrien ZFS_EXIT(zfsvfs); 223174294Sobrien return (0); 224174294Sobrien} 225174294Sobrien 226174294Sobrien/* 227174294Sobrien * Lseek support for finding holes (cmd == _FIO_SEEK_HOLE) and 228174294Sobrien * data (cmd == _FIO_SEEK_DATA). "off" is an in/out parameter. 229174294Sobrien */ 230174294Sobrienstatic int 231174294Sobrienzfs_holey(vnode_t *vp, u_long cmd, offset_t *off) 232174294Sobrien{ 233174294Sobrien znode_t *zp = VTOZ(vp); 234174294Sobrien uint64_t noff = (uint64_t)*off; /* new offset */ 235174294Sobrien uint64_t file_sz; 236174294Sobrien int error; 237174294Sobrien boolean_t hole; 238174294Sobrien 239174294Sobrien file_sz = zp->z_phys->zp_size; 240174294Sobrien if (noff >= file_sz) { 241174294Sobrien return (ENXIO); 242174294Sobrien } 243174294Sobrien 244174294Sobrien if (cmd == _FIO_SEEK_HOLE) 245174294Sobrien hole = B_TRUE; 246174294Sobrien else 247174294Sobrien hole = B_FALSE; 248174294Sobrien 249174294Sobrien error = dmu_offset_next(zp->z_zfsvfs->z_os, zp->z_id, hole, &noff); 250174294Sobrien 251174294Sobrien /* end of file? */ 252174294Sobrien if ((error == ESRCH) || (noff > file_sz)) { 253174294Sobrien /* 254174294Sobrien * Handle the virtual hole at the end of file. 255174294Sobrien */ 256174294Sobrien if (hole) { 257174294Sobrien *off = file_sz; 258174294Sobrien return (0); 259174294Sobrien } 260174294Sobrien return (ENXIO); 261174294Sobrien } 262174294Sobrien 263174294Sobrien if (noff < *off) 264174294Sobrien return (error); 265174294Sobrien *off = noff; 266174294Sobrien return (error); 267174294Sobrien} 268174294Sobrien 269174294Sobrien/* ARGSUSED */ 270174294Sobrienstatic int 271174294Sobrienzfs_ioctl(vnode_t *vp, u_long com, intptr_t data, int flag, cred_t *cred, 272174294Sobrien int *rvalp, caller_context_t *ct) 273174294Sobrien{ 274174294Sobrien offset_t off; 275174294Sobrien int error; 276174294Sobrien zfsvfs_t *zfsvfs; 277174294Sobrien znode_t *zp; 278174294Sobrien 279174294Sobrien switch (com) { 280174294Sobrien case _FIOFFS: 281174294Sobrien return (0); 282174294Sobrien 283174294Sobrien /* 284174294Sobrien * The following two ioctls are used by bfu. Faking out, 285174294Sobrien * necessary to avoid bfu errors. 286174294Sobrien */ 287174294Sobrien case _FIOGDIO: 288174294Sobrien case _FIOSDIO: 289174294Sobrien return (0); 290174294Sobrien 291174294Sobrien case _FIO_SEEK_DATA: 292174294Sobrien case _FIO_SEEK_HOLE: 293174294Sobrien if (ddi_copyin((void *)data, &off, sizeof (off), flag)) 294174294Sobrien return (EFAULT); 295174294Sobrien 296174294Sobrien zp = VTOZ(vp); 297174294Sobrien zfsvfs = zp->z_zfsvfs; 298174294Sobrien ZFS_ENTER(zfsvfs); 299174294Sobrien ZFS_VERIFY_ZP(zp); 300174294Sobrien 301174294Sobrien /* offset parameter is in/out */ 302174294Sobrien error = zfs_holey(vp, com, &off); 303174294Sobrien ZFS_EXIT(zfsvfs); 304174294Sobrien if (error) 305174294Sobrien return (error); 306174294Sobrien if (ddi_copyout(&off, (void *)data, sizeof (off), flag)) 307174294Sobrien return (EFAULT); 308174294Sobrien return (0); 309174294Sobrien } 310174294Sobrien return (ENOTTY); 311174294Sobrien} 312174294Sobrien 313174294Sobrienstatic vm_page_t 314174294Sobrienpage_lookup(vnode_t *vp, int64_t start, int64_t off, int64_t nbytes) 315174294Sobrien{ 316174294Sobrien vm_object_t obj; 317174294Sobrien vm_page_t pp; 318174294Sobrien 319174294Sobrien obj = vp->v_object; 320174294Sobrien VM_OBJECT_LOCK_ASSERT(obj, MA_OWNED); 321174294Sobrien 322174294Sobrien for (;;) { 323174294Sobrien if ((pp = vm_page_lookup(obj, OFF_TO_IDX(start))) != NULL && 324174294Sobrien vm_page_is_valid(pp, (vm_offset_t)off, nbytes)) { 325174294Sobrien if ((pp->oflags & VPO_BUSY) != 0) { 326174294Sobrien /* 327174294Sobrien * Reference the page before unlocking and 328174294Sobrien * sleeping so that the page daemon is less 329174294Sobrien * likely to reclaim it. 330174294Sobrien */ 331174294Sobrien vm_page_lock_queues(); 332174294Sobrien vm_page_flag_set(pp, PG_REFERENCED); 333174294Sobrien vm_page_sleep(pp, "zfsmwb"); 334174294Sobrien continue; 335174294Sobrien } 336174294Sobrien vm_page_busy(pp); 337174294Sobrien vm_page_undirty(pp); 338174294Sobrien } else { 339174294Sobrien if (__predict_false(obj->cache != NULL)) { 340174294Sobrien vm_page_cache_free(obj, OFF_TO_IDX(start), 341174294Sobrien OFF_TO_IDX(start) + 1); 342174294Sobrien } 343174294Sobrien pp = NULL; 344174294Sobrien } 345174294Sobrien break; 346174294Sobrien } 347174294Sobrien return (pp); 348174294Sobrien} 349174294Sobrien 350174294Sobrienstatic void 351174294Sobrienpage_unlock(vm_page_t pp) 352174294Sobrien{ 353174294Sobrien 354174294Sobrien vm_page_wakeup(pp); 355174294Sobrien} 356174294Sobrien 357174294Sobrienstatic caddr_t 358174294Sobrienzfs_map_page(vm_page_t pp, struct sf_buf **sfp) 359174294Sobrien{ 360174294Sobrien 361174294Sobrien sched_pin(); 362174294Sobrien *sfp = sf_buf_alloc(pp, SFB_CPUPRIVATE); 363174294Sobrien return ((caddr_t)sf_buf_kva(*sfp)); 364174294Sobrien} 365174294Sobrien 366174294Sobrienstatic void 367174294Sobrienzfs_unmap_page(struct sf_buf *sf) 368174294Sobrien{ 369174294Sobrien 370174294Sobrien sf_buf_free(sf); 371174294Sobrien sched_unpin(); 372174294Sobrien} 373174294Sobrien 374174294Sobrien 375174294Sobrien/* 376174294Sobrien * When a file is memory mapped, we must keep the IO data synchronized 377174294Sobrien * between the DMU cache and the memory mapped pages. What this means: 378174294Sobrien * 379174294Sobrien * On Write: If we find a memory mapped page, we write to *both* 380174294Sobrien * the page and the dmu buffer. 381174294Sobrien */ 382174294Sobrien 383174294Sobrienstatic void 384174294Sobrienupdate_pages(vnode_t *vp, int64_t start, int len, objset_t *os, uint64_t oid, 385174294Sobrien int segflg, dmu_tx_t *tx) 386174294Sobrien{ 387174294Sobrien vm_object_t obj; 388174294Sobrien struct sf_buf *sf; 389174294Sobrien int off; 390174294Sobrien 391174294Sobrien ASSERT(vp->v_mount != NULL); 392174294Sobrien obj = vp->v_object; 393174294Sobrien ASSERT(obj != NULL); 394174294Sobrien 395174294Sobrien off = start & PAGEOFFSET; 396174294Sobrien VM_OBJECT_LOCK(obj); 397174294Sobrien for (start &= PAGEMASK; len > 0; start += PAGESIZE) { 398174294Sobrien vm_page_t pp; 399174294Sobrien int nbytes = MIN(PAGESIZE - off, len); 400174294Sobrien 401174294Sobrien if ((pp = page_lookup(vp, start, off, nbytes)) != NULL) { 402174294Sobrien caddr_t va; 403174294Sobrien 404174294Sobrien VM_OBJECT_UNLOCK(obj); 405174294Sobrien va = zfs_map_page(pp, &sf); 406174294Sobrien if (segflg == UIO_NOCOPY) { 407174294Sobrien (void) dmu_write(os, oid, start+off, nbytes, 408174294Sobrien va+off, tx); 409174294Sobrien } else { 410174294Sobrien (void) dmu_read(os, oid, start+off, nbytes, 411174294Sobrien va+off, DMU_READ_PREFETCH);; 412174294Sobrien } 413174294Sobrien zfs_unmap_page(sf); 414174294Sobrien VM_OBJECT_LOCK(obj); 415174294Sobrien page_unlock(pp); 416174294Sobrien 417174294Sobrien } 418174294Sobrien len -= nbytes; 419174294Sobrien off = 0; 420174294Sobrien } 421174294Sobrien VM_OBJECT_UNLOCK(obj); 422174294Sobrien} 423174294Sobrien 424174294Sobrien/* 425174294Sobrien * When a file is memory mapped, we must keep the IO data synchronized 426174294Sobrien * between the DMU cache and the memory mapped pages. What this means: 427174294Sobrien * 428174294Sobrien * On Read: We "read" preferentially from memory mapped pages, 429174294Sobrien * else we default from the dmu buffer. 430174294Sobrien * 431174294Sobrien * NOTE: We will always "break up" the IO into PAGESIZE uiomoves when 432174294Sobrien * the file is memory mapped. 433174294Sobrien */ 434174294Sobrienstatic int 435174294Sobrienmappedread(vnode_t *vp, int nbytes, uio_t *uio) 436174294Sobrien{ 437174294Sobrien znode_t *zp = VTOZ(vp); 438174294Sobrien objset_t *os = zp->z_zfsvfs->z_os; 439174294Sobrien vm_object_t obj; 440174294Sobrien vm_page_t m; 441174294Sobrien struct sf_buf *sf; 442174294Sobrien int64_t start; 443174294Sobrien caddr_t va; 444174294Sobrien int len = nbytes; 445174294Sobrien int off; 446174294Sobrien int error = 0; 447174294Sobrien uint64_t dirbytes; 448174294Sobrien 449174294Sobrien ASSERT(vp->v_mount != NULL); 450174294Sobrien obj = vp->v_object; 451174294Sobrien ASSERT(obj != NULL); 452174294Sobrien 453174294Sobrien start = uio->uio_loffset; 454174294Sobrien off = start & PAGEOFFSET; 455174294Sobrien dirbytes = 0; 456174294Sobrien VM_OBJECT_LOCK(obj); 457174294Sobrien for (start &= PAGEMASK; len > 0; start += PAGESIZE) { 458174294Sobrien int bytes = MIN(PAGESIZE - off, len); 459174294Sobrien 460174294Sobrienagain: 461174294Sobrien if ((m = vm_page_lookup(obj, OFF_TO_IDX(start))) != NULL && 462174294Sobrien vm_page_is_valid(m, off, bytes)) { 463174294Sobrien if ((m->oflags & VPO_BUSY) != 0) { 464174294Sobrien /* 465174294Sobrien * Reference the page before unlocking and 466174294Sobrien * sleeping so that the page daemon is less 467174294Sobrien * likely to reclaim it. 468174294Sobrien */ 469174294Sobrien vm_page_lock_queues(); 470174294Sobrien vm_page_flag_set(m, PG_REFERENCED); 471174294Sobrien vm_page_sleep(m, "zfsmrb"); 472174294Sobrien goto again; 473174294Sobrien } 474174294Sobrien 475174294Sobrien vm_page_busy(m); 476174294Sobrien VM_OBJECT_UNLOCK(obj); 477174294Sobrien if (dirbytes > 0) { 478174294Sobrien error = dmu_read_uio(os, zp->z_id, uio, 479174294Sobrien dirbytes); 480174294Sobrien dirbytes = 0; 481174294Sobrien } 482174294Sobrien if (error == 0) 483174294Sobrien uiomove_fromphys(&m, off, bytes, uio); 484174294Sobrien VM_OBJECT_LOCK(obj); 485174294Sobrien vm_page_wakeup(m); 486174294Sobrien } else if (m != NULL && uio->uio_segflg == UIO_NOCOPY) { 487174294Sobrien /* 488174294Sobrien * The code below is here to make sendfile(2) work 489174294Sobrien * correctly with ZFS. As pointed out by ups@ 490174294Sobrien * sendfile(2) should be changed to use VOP_GETPAGES(), 491174294Sobrien * but it pessimize performance of sendfile/UFS, that's 492174294Sobrien * why I handle this special case in ZFS code. 493174294Sobrien */ 494174294Sobrien if ((m->oflags & VPO_BUSY) != 0) { 495174294Sobrien /* 496174294Sobrien * Reference the page before unlocking and 497174294Sobrien * sleeping so that the page daemon is less 498174294Sobrien * likely to reclaim it. 499174294Sobrien */ 500174294Sobrien vm_page_lock_queues(); 501174294Sobrien vm_page_flag_set(m, PG_REFERENCED); 502174294Sobrien vm_page_sleep(m, "zfsmrb"); 503174294Sobrien goto again; 504174294Sobrien } 505174294Sobrien vm_page_busy(m); 506174294Sobrien VM_OBJECT_UNLOCK(obj); 507174294Sobrien if (dirbytes > 0) { 508174294Sobrien error = dmu_read_uio(os, zp->z_id, uio, 509174294Sobrien dirbytes); 510174294Sobrien dirbytes = 0; 511174294Sobrien } 512174294Sobrien if (error == 0) { 513174294Sobrien sched_pin(); 514174294Sobrien sf = sf_buf_alloc(m, SFB_CPUPRIVATE); 515174294Sobrien va = (caddr_t)sf_buf_kva(sf); 516174294Sobrien error = dmu_read(os, zp->z_id, start + off, 517174294Sobrien bytes, (void *)(va + off), 518174294Sobrien DMU_READ_PREFETCH); 519174294Sobrien sf_buf_free(sf); 520174294Sobrien sched_unpin(); 521174294Sobrien } 522174294Sobrien VM_OBJECT_LOCK(obj); 523174294Sobrien if (error == 0) 524174294Sobrien vm_page_set_valid(m, off, bytes); 525174294Sobrien vm_page_wakeup(m); 526174294Sobrien if (error == 0) 527174294Sobrien uio->uio_resid -= bytes; 528174294Sobrien } else { 529174294Sobrien dirbytes += bytes; 530174294Sobrien } 531174294Sobrien len -= bytes; 532174294Sobrien off = 0; 533174294Sobrien if (error) 534174294Sobrien break; 535174294Sobrien } 536174294Sobrien VM_OBJECT_UNLOCK(obj); 537174294Sobrien if (error == 0 && dirbytes > 0) 538174294Sobrien error = dmu_read_uio(os, zp->z_id, uio, dirbytes); 539174294Sobrien return (error); 540174294Sobrien} 541174294Sobrien 542174294Sobrienoffset_t zfs_read_chunk_size = 1024 * 1024; /* Tunable */ 543174294Sobrien 544174294Sobrien/* 545174294Sobrien * Read bytes from specified file into supplied buffer. 546174294Sobrien * 547174294Sobrien * IN: vp - vnode of file to be read from. 548174294Sobrien * uio - structure supplying read location, range info, 549174294Sobrien * and return buffer. 550174294Sobrien * ioflag - SYNC flags; used to provide FRSYNC semantics. 551174294Sobrien * cr - credentials of caller. 552174294Sobrien * ct - caller context 553174294Sobrien * 554174294Sobrien * OUT: uio - updated offset and range, buffer filled. 555174294Sobrien * 556174294Sobrien * RETURN: 0 if success 557174294Sobrien * error code if failure 558174294Sobrien * 559174294Sobrien * Side Effects: 560174294Sobrien * vp - atime updated if byte count > 0 561174294Sobrien */ 562174294Sobrien/* ARGSUSED */ 563174294Sobrienstatic int 564174294Sobrienzfs_read(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cr, caller_context_t *ct) 565174294Sobrien{ 566174294Sobrien znode_t *zp = VTOZ(vp); 567174294Sobrien zfsvfs_t *zfsvfs = zp->z_zfsvfs; 568174294Sobrien objset_t *os; 569174294Sobrien ssize_t n, nbytes; 570174294Sobrien int error; 571174294Sobrien rl_t *rl; 572174294Sobrien 573174294Sobrien ZFS_ENTER(zfsvfs); 574174294Sobrien ZFS_VERIFY_ZP(zp); 575174294Sobrien os = zfsvfs->z_os; 576174294Sobrien 577174294Sobrien if (zp->z_phys->zp_flags & ZFS_AV_QUARANTINED) { 578174294Sobrien ZFS_EXIT(zfsvfs); 579174294Sobrien return (EACCES); 580174294Sobrien } 581174294Sobrien 582174294Sobrien /* 583174294Sobrien * Validate file offset 584174294Sobrien */ 585174294Sobrien if (uio->uio_loffset < (offset_t)0) { 586174294Sobrien ZFS_EXIT(zfsvfs); 587174294Sobrien return (EINVAL); 588174294Sobrien } 589174294Sobrien 590174294Sobrien /* 591174294Sobrien * Fasttrack empty reads 592174294Sobrien */ 593174294Sobrien if (uio->uio_resid == 0) { 594174294Sobrien ZFS_EXIT(zfsvfs); 595174294Sobrien return (0); 596174294Sobrien } 597174294Sobrien 598174294Sobrien /* 599174294Sobrien * Check for mandatory locks 600174294Sobrien */ 601174294Sobrien if (MANDMODE((mode_t)zp->z_phys->zp_mode)) { 602174294Sobrien if (error = chklock(vp, FREAD, 603174294Sobrien uio->uio_loffset, uio->uio_resid, uio->uio_fmode, ct)) { 604174294Sobrien ZFS_EXIT(zfsvfs); 605174294Sobrien return (error); 606174294Sobrien } 607174294Sobrien } 608174294Sobrien 609174294Sobrien /* 610174294Sobrien * If we're in FRSYNC mode, sync out this znode before reading it. 611174294Sobrien */ 612174294Sobrien if (ioflag & FRSYNC) 613174294Sobrien zil_commit(zfsvfs->z_log, zp->z_last_itx, zp->z_id); 614174294Sobrien 615174294Sobrien /* 616174294Sobrien * Lock the range against changes. 617174294Sobrien */ 618174294Sobrien rl = zfs_range_lock(zp, uio->uio_loffset, uio->uio_resid, RL_READER); 619174294Sobrien 620174294Sobrien /* 621174294Sobrien * If we are reading past end-of-file we can skip 622174294Sobrien * to the end; but we might still need to set atime. 623174294Sobrien */ 624174294Sobrien if (uio->uio_loffset >= zp->z_phys->zp_size) { 625174294Sobrien error = 0; 626174294Sobrien goto out; 627174294Sobrien } 628174294Sobrien 629174294Sobrien ASSERT(uio->uio_loffset < zp->z_phys->zp_size); 630174294Sobrien n = MIN(uio->uio_resid, zp->z_phys->zp_size - uio->uio_loffset); 631174294Sobrien 632174294Sobrien while (n > 0) { 633174294Sobrien nbytes = MIN(n, zfs_read_chunk_size - 634174294Sobrien P2PHASE(uio->uio_loffset, zfs_read_chunk_size)); 635174294Sobrien 636174294Sobrien if (vn_has_cached_data(vp)) 637174294Sobrien error = mappedread(vp, nbytes, uio); 638174294Sobrien else 639174294Sobrien error = dmu_read_uio(os, zp->z_id, uio, nbytes); 640174294Sobrien if (error) { 641174294Sobrien /* convert checksum errors into IO errors */ 642174294Sobrien if (error == ECKSUM) 643174294Sobrien error = EIO; 644174294Sobrien break; 645174294Sobrien } 646174294Sobrien 647174294Sobrien n -= nbytes; 648174294Sobrien } 649174294Sobrien 650174294Sobrienout: 651174294Sobrien zfs_range_unlock(rl); 652174294Sobrien 653174294Sobrien ZFS_ACCESSTIME_STAMP(zfsvfs, zp); 654174294Sobrien ZFS_EXIT(zfsvfs); 655174294Sobrien return (error); 656174294Sobrien} 657174294Sobrien 658174294Sobrien/* 659174294Sobrien * Fault in the pages of the first n bytes specified by the uio structure. 660174294Sobrien * 1 byte in each page is touched and the uio struct is unmodified. 661174294Sobrien * Any error will exit this routine as this is only a best 662174294Sobrien * attempt to get the pages resident. This is a copy of ufs_trans_touch(). 663174294Sobrien */ 664174294Sobrienstatic void 665174294Sobrienzfs_prefault_write(ssize_t n, struct uio *uio) 666174294Sobrien{ 667174294Sobrien struct iovec *iov; 668174294Sobrien ulong_t cnt, incr; 669174294Sobrien caddr_t p; 670174294Sobrien 671174294Sobrien if (uio->uio_segflg != UIO_USERSPACE) 672174294Sobrien return; 673174294Sobrien 674174294Sobrien iov = uio->uio_iov; 675174294Sobrien 676174294Sobrien while (n) { 677174294Sobrien cnt = MIN(iov->iov_len, n); 678174294Sobrien if (cnt == 0) { 679174294Sobrien /* empty iov entry */ 680174294Sobrien iov++; 681174294Sobrien continue; 682174294Sobrien } 683174294Sobrien n -= cnt; 684174294Sobrien /* 685174294Sobrien * touch each page in this segment. 686174294Sobrien */ 687174294Sobrien p = iov->iov_base; 688174294Sobrien while (cnt) { 689174294Sobrien if (fubyte(p) == -1) 690174294Sobrien return; 691174294Sobrien incr = MIN(cnt, PAGESIZE); 692174294Sobrien p += incr; 693174294Sobrien cnt -= incr; 694174294Sobrien } 695174294Sobrien /* 696174294Sobrien * touch the last byte in case it straddles a page. 697174294Sobrien */ 698174294Sobrien p--; 699174294Sobrien if (fubyte(p) == -1) 700174294Sobrien return; 701174294Sobrien iov++; 702174294Sobrien } 703174294Sobrien} 704174294Sobrien 705174294Sobrien/* 706174294Sobrien * Write the bytes to a file. 707174294Sobrien * 708174294Sobrien * IN: vp - vnode of file to be written to. 709174294Sobrien * uio - structure supplying write location, range info, 710174294Sobrien * and data buffer. 711174294Sobrien * ioflag - IO_APPEND flag set if in append mode. 712174294Sobrien * cr - credentials of caller. 713174294Sobrien * ct - caller context (NFS/CIFS fem monitor only) 714174294Sobrien * 715174294Sobrien * OUT: uio - updated offset and range. 716174294Sobrien * 717174294Sobrien * RETURN: 0 if success 718174294Sobrien * error code if failure 719174294Sobrien * 720174294Sobrien * Timestamps: 721174294Sobrien * vp - ctime|mtime updated if byte count > 0 722174294Sobrien */ 723174294Sobrien/* ARGSUSED */ 724174294Sobrienstatic int 725174294Sobrienzfs_write(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cr, caller_context_t *ct) 726174294Sobrien{ 727174294Sobrien znode_t *zp = VTOZ(vp); 728174294Sobrien rlim64_t limit = MAXOFFSET_T; 729174294Sobrien ssize_t start_resid = uio->uio_resid; 730174294Sobrien ssize_t tx_bytes; 731174294Sobrien uint64_t end_size; 732174294Sobrien dmu_tx_t *tx; 733174294Sobrien zfsvfs_t *zfsvfs = zp->z_zfsvfs; 734174294Sobrien zilog_t *zilog; 735174294Sobrien offset_t woff; 736174294Sobrien ssize_t n, nbytes; 737174294Sobrien rl_t *rl; 738174294Sobrien int max_blksz = zfsvfs->z_max_blksz; 739174294Sobrien uint64_t pflags; 740174294Sobrien int error; 741174294Sobrien arc_buf_t *abuf; 742174294Sobrien 743174294Sobrien /* 744174294Sobrien * Fasttrack empty write 745174294Sobrien */ 746174294Sobrien n = start_resid; 747174294Sobrien if (n == 0) 748174294Sobrien return (0); 749174294Sobrien 750174294Sobrien if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T) 751174294Sobrien limit = MAXOFFSET_T; 752174294Sobrien 753174294Sobrien ZFS_ENTER(zfsvfs); 754174294Sobrien ZFS_VERIFY_ZP(zp); 755174294Sobrien 756174294Sobrien /* 757174294Sobrien * If immutable or not appending then return EPERM 758174294Sobrien */ 759174294Sobrien pflags = zp->z_phys->zp_flags; 760174294Sobrien if ((pflags & (ZFS_IMMUTABLE | ZFS_READONLY)) || 761174294Sobrien ((pflags & ZFS_APPENDONLY) && !(ioflag & FAPPEND) && 762174294Sobrien (uio->uio_loffset < zp->z_phys->zp_size))) { 763174294Sobrien ZFS_EXIT(zfsvfs); 764174294Sobrien return (EPERM); 765174294Sobrien } 766174294Sobrien 767174294Sobrien zilog = zfsvfs->z_log; 768174294Sobrien 769174294Sobrien /* 770174294Sobrien * Pre-fault the pages to ensure slow (eg NFS) pages 771174294Sobrien * don't hold up txg. 772174294Sobrien */ 773174294Sobrien zfs_prefault_write(n, uio); 774174294Sobrien 775174294Sobrien /* 776174294Sobrien * If in append mode, set the io offset pointer to eof. 777174294Sobrien */ 778174294Sobrien if (ioflag & IO_APPEND) { 779174294Sobrien /* 780174294Sobrien * Range lock for a file append: 781174294Sobrien * The value for the start of range will be determined by 782174294Sobrien * zfs_range_lock() (to guarantee append semantics). 783174294Sobrien * If this write will cause the block size to increase, 784174294Sobrien * zfs_range_lock() will lock the entire file, so we must 785174294Sobrien * later reduce the range after we grow the block size. 786174294Sobrien */ 787174294Sobrien rl = zfs_range_lock(zp, 0, n, RL_APPEND); 788174294Sobrien if (rl->r_len == UINT64_MAX) { 789174294Sobrien /* overlocked, zp_size can't change */ 790174294Sobrien woff = uio->uio_loffset = zp->z_phys->zp_size; 791174294Sobrien } else { 792174294Sobrien woff = uio->uio_loffset = rl->r_off; 793174294Sobrien } 794174294Sobrien } else { 795174294Sobrien woff = uio->uio_loffset; 796174294Sobrien /* 797174294Sobrien * Validate file offset 798174294Sobrien */ 799174294Sobrien if (woff < 0) { 800174294Sobrien ZFS_EXIT(zfsvfs); 801174294Sobrien return (EINVAL); 802174294Sobrien } 803174294Sobrien 804174294Sobrien /* 805174294Sobrien * If we need to grow the block size then zfs_range_lock() 806174294Sobrien * will lock a wider range than we request here. 807174294Sobrien * Later after growing the block size we reduce the range. 808174294Sobrien */ 809174294Sobrien rl = zfs_range_lock(zp, woff, n, RL_WRITER); 810174294Sobrien } 811174294Sobrien 812174294Sobrien if (woff >= limit) { 813174294Sobrien zfs_range_unlock(rl); 814174294Sobrien ZFS_EXIT(zfsvfs); 815174294Sobrien return (EFBIG); 816174294Sobrien } 817174294Sobrien 818174294Sobrien if ((woff + n) > limit || woff > (limit - n)) 819174294Sobrien n = limit - woff; 820174294Sobrien 821174294Sobrien /* 822174294Sobrien * Check for mandatory locks 823174294Sobrien */ 824174294Sobrien if (MANDMODE((mode_t)zp->z_phys->zp_mode) && 825174294Sobrien (error = chklock(vp, FWRITE, woff, n, uio->uio_fmode, ct)) != 0) { 826174294Sobrien zfs_range_unlock(rl); 827174294Sobrien ZFS_EXIT(zfsvfs); 828174294Sobrien return (error); 829174294Sobrien } 830174294Sobrien end_size = MAX(zp->z_phys->zp_size, woff + n); 831174294Sobrien 832174294Sobrien /* 833174294Sobrien * Write the file in reasonable size chunks. Each chunk is written 834174294Sobrien * in a separate transaction; this keeps the intent log records small 835174294Sobrien * and allows us to do more fine-grained space accounting. 836174294Sobrien */ 837174294Sobrien while (n > 0) { 838174294Sobrien abuf = NULL; 839174294Sobrien woff = uio->uio_loffset; 840174294Sobrien 841174294Sobrienagain: 842174294Sobrien if (zfs_usergroup_overquota(zfsvfs, 843174294Sobrien B_FALSE, zp->z_phys->zp_uid) || 844174294Sobrien zfs_usergroup_overquota(zfsvfs, 845174294Sobrien B_TRUE, zp->z_phys->zp_gid)) { 846174294Sobrien if (abuf != NULL) 847174294Sobrien dmu_return_arcbuf(abuf); 848174294Sobrien error = EDQUOT; 849174294Sobrien break; 850174294Sobrien } 851174294Sobrien 852174294Sobrien /* 853174294Sobrien * If dmu_assign_arcbuf() is expected to execute with minimum 854174294Sobrien * overhead loan an arc buffer and copy user data to it before 855174294Sobrien * we enter a txg. This avoids holding a txg forever while we 856174294Sobrien * pagefault on a hanging NFS server mapping. 857174294Sobrien */ 858174294Sobrien if (abuf == NULL && n >= max_blksz && 859174294Sobrien woff >= zp->z_phys->zp_size && 860174294Sobrien P2PHASE(woff, max_blksz) == 0 && 861174294Sobrien zp->z_blksz == max_blksz) { 862174294Sobrien size_t cbytes; 863174294Sobrien 864174294Sobrien abuf = dmu_request_arcbuf(zp->z_dbuf, max_blksz); 865174294Sobrien ASSERT(abuf != NULL); 866174294Sobrien ASSERT(arc_buf_size(abuf) == max_blksz); 867174294Sobrien if (error = uiocopy(abuf->b_data, max_blksz, 868174294Sobrien UIO_WRITE, uio, &cbytes)) { 869174294Sobrien dmu_return_arcbuf(abuf); 870174294Sobrien break; 871174294Sobrien } 872174294Sobrien ASSERT(cbytes == max_blksz); 873174294Sobrien } 874174294Sobrien 875174294Sobrien /* 876174294Sobrien * Start a transaction. 877174294Sobrien */ 878174294Sobrien tx = dmu_tx_create(zfsvfs->z_os); 879174294Sobrien dmu_tx_hold_bonus(tx, zp->z_id); 880174294Sobrien dmu_tx_hold_write(tx, zp->z_id, woff, MIN(n, max_blksz)); 881174294Sobrien error = dmu_tx_assign(tx, TXG_NOWAIT); 882174294Sobrien if (error) { 883174294Sobrien if (error == ERESTART) { 884174294Sobrien dmu_tx_wait(tx); 885174294Sobrien dmu_tx_abort(tx); 886174294Sobrien goto again; 887174294Sobrien } 888174294Sobrien dmu_tx_abort(tx); 889174294Sobrien if (abuf != NULL) 890174294Sobrien dmu_return_arcbuf(abuf); 891174294Sobrien break; 892174294Sobrien } 893174294Sobrien 894174294Sobrien /* 895174294Sobrien * If zfs_range_lock() over-locked we grow the blocksize 896174294Sobrien * and then reduce the lock range. This will only happen 897174294Sobrien * on the first iteration since zfs_range_reduce() will 898174294Sobrien * shrink down r_len to the appropriate size. 899174294Sobrien */ 900174294Sobrien if (rl->r_len == UINT64_MAX) { 901174294Sobrien uint64_t new_blksz; 902174294Sobrien 903174294Sobrien if (zp->z_blksz > max_blksz) { 904174294Sobrien ASSERT(!ISP2(zp->z_blksz)); 905174294Sobrien new_blksz = MIN(end_size, SPA_MAXBLOCKSIZE); 906174294Sobrien } else { 907174294Sobrien new_blksz = MIN(end_size, max_blksz); 908174294Sobrien } 909174294Sobrien zfs_grow_blocksize(zp, new_blksz, tx); 910174294Sobrien zfs_range_reduce(rl, woff, n); 911174294Sobrien } 912174294Sobrien 913174294Sobrien /* 914174294Sobrien * XXX - should we really limit each write to z_max_blksz? 915174294Sobrien * Perhaps we should use SPA_MAXBLOCKSIZE chunks? 916174294Sobrien */ 917174294Sobrien nbytes = MIN(n, max_blksz - P2PHASE(woff, max_blksz)); 918174294Sobrien 919174294Sobrien if (woff + nbytes > zp->z_phys->zp_size) 920174294Sobrien vnode_pager_setsize(vp, woff + nbytes); 921174294Sobrien 922174294Sobrien if (abuf == NULL) { 923174294Sobrien tx_bytes = uio->uio_resid; 924174294Sobrien error = dmu_write_uio(zfsvfs->z_os, zp->z_id, uio, 925174294Sobrien nbytes, tx); 926174294Sobrien tx_bytes -= uio->uio_resid; 927174294Sobrien } else { 928174294Sobrien tx_bytes = nbytes; 929174294Sobrien ASSERT(tx_bytes == max_blksz); 930174294Sobrien dmu_assign_arcbuf(zp->z_dbuf, woff, abuf, tx); 931174294Sobrien ASSERT(tx_bytes <= uio->uio_resid); 932174294Sobrien uioskip(uio, tx_bytes); 933174294Sobrien } 934174294Sobrien 935174294Sobrien if (tx_bytes && vn_has_cached_data(vp)) { 936174294Sobrien update_pages(vp, woff, tx_bytes, zfsvfs->z_os, 937174294Sobrien zp->z_id, uio->uio_segflg, tx); 938174294Sobrien } 939174294Sobrien 940174294Sobrien /* 941174294Sobrien * If we made no progress, we're done. If we made even 942174294Sobrien * partial progress, update the znode and ZIL accordingly. 943174294Sobrien */ 944174294Sobrien if (tx_bytes == 0) { 945174294Sobrien dmu_tx_commit(tx); 946174294Sobrien ASSERT(error != 0); 947174294Sobrien break; 948174294Sobrien } 949174294Sobrien 950174294Sobrien /* 951174294Sobrien * Clear Set-UID/Set-GID bits on successful write if not 952174294Sobrien * privileged and at least one of the excute bits is set. 953174294Sobrien * 954174294Sobrien * It would be nice to to this after all writes have 955174294Sobrien * been done, but that would still expose the ISUID/ISGID 956174294Sobrien * to another app after the partial write is committed. 957174294Sobrien * 958174294Sobrien * Note: we don't call zfs_fuid_map_id() here because 959174294Sobrien * user 0 is not an ephemeral uid. 960174294Sobrien */ 961174294Sobrien mutex_enter(&zp->z_acl_lock); 962174294Sobrien if ((zp->z_phys->zp_mode & (S_IXUSR | (S_IXUSR >> 3) | 963174294Sobrien (S_IXUSR >> 6))) != 0 && 964174294Sobrien (zp->z_phys->zp_mode & (S_ISUID | S_ISGID)) != 0 && 965174294Sobrien secpolicy_vnode_setid_retain(vp, cr, 966174294Sobrien (zp->z_phys->zp_mode & S_ISUID) != 0 && 967174294Sobrien zp->z_phys->zp_uid == 0) != 0) { 968174294Sobrien zp->z_phys->zp_mode &= ~(S_ISUID | S_ISGID); 969174294Sobrien } 970174294Sobrien mutex_exit(&zp->z_acl_lock); 971174294Sobrien 972174294Sobrien /* 973174294Sobrien * Update time stamp. NOTE: This marks the bonus buffer as 974174294Sobrien * dirty, so we don't have to do it again for zp_size. 975174294Sobrien */ 976174294Sobrien zfs_time_stamper(zp, CONTENT_MODIFIED, tx); 977174294Sobrien 978174294Sobrien /* 979174294Sobrien * Update the file size (zp_size) if it has changed; 980174294Sobrien * account for possible concurrent updates. 981174294Sobrien */ 982174294Sobrien while ((end_size = zp->z_phys->zp_size) < uio->uio_loffset) 983174294Sobrien (void) atomic_cas_64(&zp->z_phys->zp_size, end_size, 984174294Sobrien uio->uio_loffset); 985174294Sobrien zfs_log_write(zilog, tx, TX_WRITE, zp, woff, tx_bytes, ioflag); 986174294Sobrien dmu_tx_commit(tx); 987174294Sobrien 988174294Sobrien if (error != 0) 989174294Sobrien break; 990174294Sobrien ASSERT(tx_bytes == nbytes); 991174294Sobrien n -= nbytes; 992174294Sobrien } 993174294Sobrien 994174294Sobrien zfs_range_unlock(rl); 995174294Sobrien 996174294Sobrien /* 997174294Sobrien * If we're in replay mode, or we made no progress, return error. 998174294Sobrien * Otherwise, it's at least a partial write, so it's successful. 999174294Sobrien */ 1000174294Sobrien if (zfsvfs->z_replay || uio->uio_resid == start_resid) { 1001174294Sobrien ZFS_EXIT(zfsvfs); 1002174294Sobrien return (error); 1003174294Sobrien } 1004174294Sobrien 1005174294Sobrien if (ioflag & (FSYNC | FDSYNC)) 1006174294Sobrien zil_commit(zilog, zp->z_last_itx, zp->z_id); 1007174294Sobrien 1008174294Sobrien ZFS_EXIT(zfsvfs); 1009174294Sobrien return (0); 1010174294Sobrien} 1011174294Sobrien 1012174294Sobrienvoid 1013174294Sobrienzfs_get_done(dmu_buf_t *db, void *vzgd) 1014174294Sobrien{ 1015174294Sobrien zgd_t *zgd = (zgd_t *)vzgd; 1016174294Sobrien rl_t *rl = zgd->zgd_rl; 1017174294Sobrien vnode_t *vp = ZTOV(rl->r_zp); 1018174294Sobrien objset_t *os = rl->r_zp->z_zfsvfs->z_os; 1019174294Sobrien int vfslocked; 1020174294Sobrien 1021174294Sobrien vfslocked = VFS_LOCK_GIANT(vp->v_vfsp); 1022174294Sobrien dmu_buf_rele(db, vzgd); 1023174294Sobrien zfs_range_unlock(rl); 1024174294Sobrien /* 1025174294Sobrien * Release the vnode asynchronously as we currently have the 1026174294Sobrien * txg stopped from syncing. 1027174294Sobrien */ 1028174294Sobrien VN_RELE_ASYNC(vp, dsl_pool_vnrele_taskq(dmu_objset_pool(os))); 1029174294Sobrien zil_add_block(zgd->zgd_zilog, zgd->zgd_bp); 1030174294Sobrien kmem_free(zgd, sizeof (zgd_t)); 1031174294Sobrien VFS_UNLOCK_GIANT(vfslocked); 1032174294Sobrien} 1033174294Sobrien 1034174294Sobrien/* 1035174294Sobrien * Get data to generate a TX_WRITE intent log record. 1036174294Sobrien */ 1037174294Sobrienint 1038174294Sobrienzfs_get_data(void *arg, lr_write_t *lr, char *buf, zio_t *zio) 1039174294Sobrien{ 1040174294Sobrien zfsvfs_t *zfsvfs = arg; 1041174294Sobrien objset_t *os = zfsvfs->z_os; 1042174294Sobrien znode_t *zp; 1043174294Sobrien uint64_t off = lr->lr_offset; 1044174294Sobrien dmu_buf_t *db; 1045174294Sobrien rl_t *rl; 1046174294Sobrien zgd_t *zgd; 1047174294Sobrien int dlen = lr->lr_length; /* length of user data */ 1048174294Sobrien int error = 0; 1049174294Sobrien 1050174294Sobrien ASSERT(zio); 1051174294Sobrien ASSERT(dlen != 0); 1052174294Sobrien 1053174294Sobrien /* 1054174294Sobrien * Nothing to do if the file has been removed 1055174294Sobrien */ 1056174294Sobrien if (zfs_zget(zfsvfs, lr->lr_foid, &zp) != 0) 1057174294Sobrien return (ENOENT); 1058174294Sobrien if (zp->z_unlinked) { 1059174294Sobrien /* 1060174294Sobrien * Release the vnode asynchronously as we currently have the 1061174294Sobrien * txg stopped from syncing. 1062174294Sobrien */ 1063174294Sobrien VN_RELE_ASYNC(ZTOV(zp), 1064174294Sobrien dsl_pool_vnrele_taskq(dmu_objset_pool(os))); 1065174294Sobrien return (ENOENT); 1066174294Sobrien } 1067174294Sobrien 1068174294Sobrien /* 1069174294Sobrien * Write records come in two flavors: immediate and indirect. 1070174294Sobrien * For small writes it's cheaper to store the data with the 1071174294Sobrien * log record (immediate); for large writes it's cheaper to 1072174294Sobrien * sync the data and get a pointer to it (indirect) so that 1073174294Sobrien * we don't have to write the data twice. 1074174294Sobrien */ 1075174294Sobrien if (buf != NULL) { /* immediate write */ 1076174294Sobrien rl = zfs_range_lock(zp, off, dlen, RL_READER); 1077174294Sobrien /* test for truncation needs to be done while range locked */ 1078174294Sobrien if (off >= zp->z_phys->zp_size) { 1079174294Sobrien error = ENOENT; 1080174294Sobrien goto out; 1081174294Sobrien } 1082174294Sobrien VERIFY(0 == dmu_read(os, lr->lr_foid, off, dlen, buf, 1083174294Sobrien DMU_READ_NO_PREFETCH)); 1084174294Sobrien } else { /* indirect write */ 1085174294Sobrien uint64_t boff; /* block starting offset */ 1086174294Sobrien 1087174294Sobrien /* 1088174294Sobrien * Have to lock the whole block to ensure when it's 1089174294Sobrien * written out and it's checksum is being calculated 1090174294Sobrien * that no one can change the data. We need to re-check 1091174294Sobrien * blocksize after we get the lock in case it's changed! 1092174294Sobrien */ 1093174294Sobrien for (;;) { 1094174294Sobrien if (ISP2(zp->z_blksz)) { 1095174294Sobrien boff = P2ALIGN_TYPED(off, zp->z_blksz, 1096174294Sobrien uint64_t); 1097174294Sobrien } else { 1098174294Sobrien boff = 0; 1099174294Sobrien } 1100174294Sobrien dlen = zp->z_blksz; 1101174294Sobrien rl = zfs_range_lock(zp, boff, dlen, RL_READER); 1102174294Sobrien if (zp->z_blksz == dlen) 1103174294Sobrien break; 1104174294Sobrien zfs_range_unlock(rl); 1105174294Sobrien } 1106174294Sobrien /* test for truncation needs to be done while range locked */ 1107174294Sobrien if (off >= zp->z_phys->zp_size) { 1108174294Sobrien error = ENOENT; 1109174294Sobrien goto out; 1110174294Sobrien } 1111174294Sobrien zgd = (zgd_t *)kmem_alloc(sizeof (zgd_t), KM_SLEEP); 1112174294Sobrien zgd->zgd_rl = rl; 1113174294Sobrien zgd->zgd_zilog = zfsvfs->z_log; 1114174294Sobrien zgd->zgd_bp = &lr->lr_blkptr; 1115174294Sobrien VERIFY(0 == dmu_buf_hold(os, lr->lr_foid, boff, zgd, &db)); 1116174294Sobrien ASSERT(boff == db->db_offset); 1117174294Sobrien lr->lr_blkoff = off - boff; 1118174294Sobrien error = dmu_sync(zio, db, &lr->lr_blkptr, 1119174294Sobrien lr->lr_common.lrc_txg, zfs_get_done, zgd); 1120174294Sobrien ASSERT((error && error != EINPROGRESS) || 1121174294Sobrien lr->lr_length <= zp->z_blksz); 1122174294Sobrien if (error == 0) { 1123174294Sobrien /* 1124174294Sobrien * dmu_sync() can compress a block of zeros to a null 1125174294Sobrien * blkptr but the block size still needs to be passed 1126174294Sobrien * through to replay. 1127174294Sobrien */ 1128174294Sobrien BP_SET_LSIZE(&lr->lr_blkptr, db->db_size); 1129174294Sobrien zil_add_block(zfsvfs->z_log, &lr->lr_blkptr); 1130174294Sobrien } 1131174294Sobrien 1132174294Sobrien /* 1133174294Sobrien * If we get EINPROGRESS, then we need to wait for a 1134174294Sobrien * write IO initiated by dmu_sync() to complete before 1135174294Sobrien * we can release this dbuf. We will finish everything 1136174294Sobrien * up in the zfs_get_done() callback. 1137174294Sobrien */ 1138174294Sobrien if (error == EINPROGRESS) { 1139174294Sobrien return (0); 1140174294Sobrien } else if (error == EALREADY) { 1141174294Sobrien lr->lr_common.lrc_txtype = TX_WRITE2; 1142174294Sobrien error = 0; 1143174294Sobrien } 1144174294Sobrien dmu_buf_rele(db, zgd); 1145174294Sobrien kmem_free(zgd, sizeof (zgd_t)); 1146174294Sobrien } 1147174294Sobrienout: 1148174294Sobrien zfs_range_unlock(rl); 1149174294Sobrien /* 1150174294Sobrien * Release the vnode asynchronously as we currently have the 1151174294Sobrien * txg stopped from syncing. 1152174294Sobrien */ 1153174294Sobrien VN_RELE_ASYNC(ZTOV(zp), dsl_pool_vnrele_taskq(dmu_objset_pool(os))); 1154174294Sobrien return (error); 1155174294Sobrien} 1156174294Sobrien 1157174294Sobrien/*ARGSUSED*/ 1158174294Sobrienstatic int 1159174294Sobrienzfs_access(vnode_t *vp, int mode, int flag, cred_t *cr, 1160174294Sobrien caller_context_t *ct) 1161174294Sobrien{ 1162174294Sobrien znode_t *zp = VTOZ(vp); 1163174294Sobrien zfsvfs_t *zfsvfs = zp->z_zfsvfs; 1164174294Sobrien int error; 1165174294Sobrien 1166174294Sobrien ZFS_ENTER(zfsvfs); 1167174294Sobrien ZFS_VERIFY_ZP(zp); 1168174294Sobrien 1169174294Sobrien if (flag & V_ACE_MASK) 1170174294Sobrien error = zfs_zaccess(zp, mode, flag, B_FALSE, cr); 1171174294Sobrien else 1172174294Sobrien error = zfs_zaccess_rwx(zp, mode, flag, cr); 1173174294Sobrien 1174174294Sobrien ZFS_EXIT(zfsvfs); 1175174294Sobrien return (error); 1176174294Sobrien} 1177174294Sobrien 1178174294Sobrien/* 1179174294Sobrien * If vnode is for a device return a specfs vnode instead. 1180174294Sobrien */ 1181174294Sobrienstatic int 1182174294Sobrienspecvp_check(vnode_t **vpp, cred_t *cr) 1183174294Sobrien{ 1184174294Sobrien int error = 0; 1185174294Sobrien 1186174294Sobrien if (IS_DEVVP(*vpp)) { 1187174294Sobrien struct vnode *svp; 1188174294Sobrien 1189174294Sobrien svp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type, cr); 1190174294Sobrien VN_RELE(*vpp); 1191174294Sobrien if (svp == NULL) 1192174294Sobrien error = ENOSYS; 1193174294Sobrien *vpp = svp; 1194174294Sobrien } 1195174294Sobrien return (error); 1196174294Sobrien} 1197174294Sobrien 1198174294Sobrien 1199174294Sobrien/* 1200174294Sobrien * Lookup an entry in a directory, or an extended attribute directory. 1201174294Sobrien * If it exists, return a held vnode reference for it. 1202174294Sobrien * 1203174294Sobrien * IN: dvp - vnode of directory to search. 1204174294Sobrien * nm - name of entry to lookup. 1205174294Sobrien * pnp - full pathname to lookup [UNUSED]. 1206174294Sobrien * flags - LOOKUP_XATTR set if looking for an attribute. 1207174294Sobrien * rdir - root directory vnode [UNUSED]. 1208174294Sobrien * cr - credentials of caller. 1209174294Sobrien * ct - caller context 1210174294Sobrien * direntflags - directory lookup flags 1211174294Sobrien * realpnp - returned pathname. 1212174294Sobrien * 1213174294Sobrien * OUT: vpp - vnode of located entry, NULL if not found. 1214174294Sobrien * 1215174294Sobrien * RETURN: 0 if success 1216174294Sobrien * error code if failure 1217174294Sobrien * 1218174294Sobrien * Timestamps: 1219174294Sobrien * NA 1220174294Sobrien */ 1221174294Sobrien/* ARGSUSED */ 1222174294Sobrienstatic int 1223174294Sobrienzfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct componentname *cnp, 1224174294Sobrien int nameiop, cred_t *cr, kthread_t *td, int flags) 1225174294Sobrien{ 1226174294Sobrien znode_t *zdp = VTOZ(dvp); 1227174294Sobrien zfsvfs_t *zfsvfs = zdp->z_zfsvfs; 1228174294Sobrien int error = 0; 1229174294Sobrien int *direntflags = NULL; 1230174294Sobrien void *realpnp = NULL; 1231174294Sobrien 1232174294Sobrien /* fast path */ 1233174294Sobrien if (!(flags & (LOOKUP_XATTR | FIGNORECASE))) { 1234174294Sobrien 1235174294Sobrien if (dvp->v_type != VDIR) { 1236174294Sobrien return (ENOTDIR); 1237174294Sobrien } else if (zdp->z_dbuf == NULL) { 1238174294Sobrien return (EIO); 1239174294Sobrien } 1240174294Sobrien 1241174294Sobrien if (nm[0] == 0 || (nm[0] == '.' && nm[1] == '\0')) { 1242174294Sobrien error = zfs_fastaccesschk_execute(zdp, cr); 1243174294Sobrien if (!error) { 1244174294Sobrien *vpp = dvp; 1245174294Sobrien VN_HOLD(*vpp); 1246174294Sobrien return (0); 1247174294Sobrien } 1248174294Sobrien return (error); 1249174294Sobrien } else { 1250174294Sobrien vnode_t *tvp = dnlc_lookup(dvp, nm); 1251174294Sobrien 1252174294Sobrien if (tvp) { 1253174294Sobrien error = zfs_fastaccesschk_execute(zdp, cr); 1254174294Sobrien if (error) { 1255174294Sobrien VN_RELE(tvp); 1256174294Sobrien return (error); 1257174294Sobrien } 1258174294Sobrien if (tvp == DNLC_NO_VNODE) { 1259174294Sobrien VN_RELE(tvp); 1260174294Sobrien return (ENOENT); 1261174294Sobrien } else { 1262174294Sobrien *vpp = tvp; 1263174294Sobrien return (specvp_check(vpp, cr)); 1264174294Sobrien } 1265174294Sobrien } 1266174294Sobrien } 1267174294Sobrien } 1268174294Sobrien 1269174294Sobrien DTRACE_PROBE2(zfs__fastpath__lookup__miss, vnode_t *, dvp, char *, nm); 1270174294Sobrien 1271174294Sobrien ZFS_ENTER(zfsvfs); 1272174294Sobrien ZFS_VERIFY_ZP(zdp); 1273174294Sobrien 1274174294Sobrien *vpp = NULL; 1275174294Sobrien 1276174294Sobrien if (flags & LOOKUP_XATTR) { 1277174294Sobrien#ifdef TODO 1278174294Sobrien /* 1279174294Sobrien * If the xattr property is off, refuse the lookup request. 1280174294Sobrien */ 1281174294Sobrien if (!(zfsvfs->z_vfs->vfs_flag & VFS_XATTR)) { 1282174294Sobrien ZFS_EXIT(zfsvfs); 1283174294Sobrien return (EINVAL); 1284174294Sobrien } 1285174294Sobrien#endif 1286174294Sobrien 1287174294Sobrien /* 1288174294Sobrien * We don't allow recursive attributes.. 1289174294Sobrien * Maybe someday we will. 1290174294Sobrien */ 1291174294Sobrien if (zdp->z_phys->zp_flags & ZFS_XATTR) { 1292174294Sobrien ZFS_EXIT(zfsvfs); 1293174294Sobrien return (EINVAL); 1294174294Sobrien } 1295174294Sobrien 1296174294Sobrien if (error = zfs_get_xattrdir(VTOZ(dvp), vpp, cr, flags)) { 1297174294Sobrien ZFS_EXIT(zfsvfs); 1298174294Sobrien return (error); 1299174294Sobrien } 1300174294Sobrien 1301174294Sobrien /* 1302174294Sobrien * Do we have permission to get into attribute directory? 1303174294Sobrien */ 1304174294Sobrien 1305174294Sobrien if (error = zfs_zaccess(VTOZ(*vpp), ACE_EXECUTE, 0, 1306174294Sobrien B_FALSE, cr)) { 1307174294Sobrien VN_RELE(*vpp); 1308174294Sobrien *vpp = NULL; 1309174294Sobrien } 1310174294Sobrien 1311174294Sobrien ZFS_EXIT(zfsvfs); 1312174294Sobrien return (error); 1313174294Sobrien } 1314174294Sobrien 1315174294Sobrien if (dvp->v_type != VDIR) { 1316174294Sobrien ZFS_EXIT(zfsvfs); 1317174294Sobrien return (ENOTDIR); 1318174294Sobrien } 1319174294Sobrien 1320174294Sobrien /* 1321174294Sobrien * Check accessibility of directory. 1322174294Sobrien */ 1323174294Sobrien 1324174294Sobrien if (error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr)) { 1325174294Sobrien ZFS_EXIT(zfsvfs); 1326174294Sobrien return (error); 1327174294Sobrien } 1328174294Sobrien 1329174294Sobrien if (zfsvfs->z_utf8 && u8_validate(nm, strlen(nm), 1330174294Sobrien NULL, U8_VALIDATE_ENTIRE, &error) < 0) { 1331174294Sobrien ZFS_EXIT(zfsvfs); 1332174294Sobrien return (EILSEQ); 1333174294Sobrien } 1334174294Sobrien 1335174294Sobrien error = zfs_dirlook(zdp, nm, vpp, flags, direntflags, realpnp); 1336174294Sobrien if (error == 0) 1337174294Sobrien error = specvp_check(vpp, cr); 1338174294Sobrien 1339174294Sobrien /* Translate errors and add SAVENAME when needed. */ 1340174294Sobrien if (cnp->cn_flags & ISLASTCN) { 1341174294Sobrien switch (nameiop) { 1342174294Sobrien case CREATE: 1343174294Sobrien case RENAME: 1344174294Sobrien if (error == ENOENT) { 1345174294Sobrien error = EJUSTRETURN; 1346174294Sobrien cnp->cn_flags |= SAVENAME; 1347174294Sobrien break; 1348174294Sobrien } 1349174294Sobrien /* FALLTHROUGH */ 1350174294Sobrien case DELETE: 1351174294Sobrien if (error == 0) 1352174294Sobrien cnp->cn_flags |= SAVENAME; 1353174294Sobrien break; 1354174294Sobrien } 1355174294Sobrien } 1356174294Sobrien if (error == 0 && (nm[0] != '.' || nm[1] != '\0')) { 1357174294Sobrien int ltype = 0; 1358174294Sobrien 1359174294Sobrien if (cnp->cn_flags & ISDOTDOT) { 1360174294Sobrien ltype = VOP_ISLOCKED(dvp); 1361174294Sobrien VOP_UNLOCK(dvp, 0); 1362174294Sobrien } 1363174294Sobrien ZFS_EXIT(zfsvfs); 1364174294Sobrien error = vn_lock(*vpp, cnp->cn_lkflags); 1365174294Sobrien if (cnp->cn_flags & ISDOTDOT) 1366174294Sobrien vn_lock(dvp, ltype | LK_RETRY); 1367174294Sobrien if (error != 0) { 1368174294Sobrien VN_RELE(*vpp); 1369174294Sobrien *vpp = NULL; 1370174294Sobrien return (error); 1371174294Sobrien } 1372174294Sobrien } else { 1373174294Sobrien ZFS_EXIT(zfsvfs); 1374174294Sobrien } 1375174294Sobrien 1376174294Sobrien#ifdef FREEBSD_NAMECACHE 1377174294Sobrien /* 1378174294Sobrien * Insert name into cache (as non-existent) if appropriate. 1379174294Sobrien */ 1380174294Sobrien if (error == ENOENT && (cnp->cn_flags & MAKEENTRY) && nameiop != CREATE) 1381174294Sobrien cache_enter(dvp, *vpp, cnp); 1382174294Sobrien /* 1383174294Sobrien * Insert name into cache if appropriate. 1384174294Sobrien */ 1385174294Sobrien if (error == 0 && (cnp->cn_flags & MAKEENTRY)) { 1386174294Sobrien if (!(cnp->cn_flags & ISLASTCN) || 1387174294Sobrien (nameiop != DELETE && nameiop != RENAME)) { 1388174294Sobrien cache_enter(dvp, *vpp, cnp); 1389174294Sobrien } 1390174294Sobrien } 1391174294Sobrien#endif 1392174294Sobrien 1393174294Sobrien return (error); 1394174294Sobrien} 1395174294Sobrien 1396174294Sobrien/* 1397174294Sobrien * Attempt to create a new entry in a directory. If the entry 1398174294Sobrien * already exists, truncate the file if permissible, else return 1399174294Sobrien * an error. Return the vp of the created or trunc'd file. 1400174294Sobrien * 1401174294Sobrien * IN: dvp - vnode of directory to put new file entry in. 1402174294Sobrien * name - name of new file entry. 1403174294Sobrien * vap - attributes of new file. 1404174294Sobrien * excl - flag indicating exclusive or non-exclusive mode. 1405174294Sobrien * mode - mode to open file with. 1406174294Sobrien * cr - credentials of caller. 1407174294Sobrien * flag - large file flag [UNUSED]. 1408174294Sobrien * ct - caller context 1409174294Sobrien * vsecp - ACL to be set 1410174294Sobrien * 1411174294Sobrien * OUT: vpp - vnode of created or trunc'd entry. 1412174294Sobrien * 1413174294Sobrien * RETURN: 0 if success 1414174294Sobrien * error code if failure 1415174294Sobrien * 1416174294Sobrien * Timestamps: 1417174294Sobrien * dvp - ctime|mtime updated if new entry created 1418174294Sobrien * vp - ctime|mtime always, atime if new 1419174294Sobrien */ 1420174294Sobrien 1421174294Sobrien/* ARGSUSED */ 1422174294Sobrienstatic int 1423174294Sobrienzfs_create(vnode_t *dvp, char *name, vattr_t *vap, int excl, int mode, 1424174294Sobrien vnode_t **vpp, cred_t *cr, kthread_t *td) 1425174294Sobrien{ 1426174294Sobrien znode_t *zp, *dzp = VTOZ(dvp); 1427174294Sobrien zfsvfs_t *zfsvfs = dzp->z_zfsvfs; 1428174294Sobrien zilog_t *zilog; 1429174294Sobrien objset_t *os; 1430174294Sobrien zfs_dirlock_t *dl; 1431174294Sobrien dmu_tx_t *tx; 1432174294Sobrien int error; 1433174294Sobrien ksid_t *ksid; 1434174294Sobrien uid_t uid; 1435174294Sobrien gid_t gid = crgetgid(cr); 1436174294Sobrien zfs_acl_ids_t acl_ids; 1437174294Sobrien boolean_t fuid_dirtied; 1438174294Sobrien void *vsecp = NULL; 1439174294Sobrien int flag = 0; 1440174294Sobrien 1441174294Sobrien /* 1442174294Sobrien * If we have an ephemeral id, ACL, or XVATTR then 1443174294Sobrien * make sure file system is at proper version 1444174294Sobrien */ 1445174294Sobrien 1446174294Sobrien ksid = crgetsid(cr, KSID_OWNER); 1447174294Sobrien if (ksid) 1448174294Sobrien uid = ksid_getid(ksid); 1449174294Sobrien else 1450174294Sobrien uid = crgetuid(cr); 1451174294Sobrien if (zfsvfs->z_use_fuids == B_FALSE && 1452174294Sobrien (vsecp || (vap->va_mask & AT_XVATTR) || 1453174294Sobrien IS_EPHEMERAL(crgetuid(cr)) || IS_EPHEMERAL(crgetgid(cr)))) 1454174294Sobrien return (EINVAL); 1455174294Sobrien 1456174294Sobrien ZFS_ENTER(zfsvfs); 1457174294Sobrien ZFS_VERIFY_ZP(dzp); 1458174294Sobrien os = zfsvfs->z_os; 1459174294Sobrien zilog = zfsvfs->z_log; 1460174294Sobrien 1461174294Sobrien if (zfsvfs->z_utf8 && u8_validate(name, strlen(name), 1462174294Sobrien NULL, U8_VALIDATE_ENTIRE, &error) < 0) { 1463174294Sobrien ZFS_EXIT(zfsvfs); 1464174294Sobrien return (EILSEQ); 1465174294Sobrien } 1466174294Sobrien 1467174294Sobrien if (vap->va_mask & AT_XVATTR) { 1468174294Sobrien if ((error = secpolicy_xvattr(dvp, (xvattr_t *)vap, 1469174294Sobrien crgetuid(cr), cr, vap->va_type)) != 0) { 1470174294Sobrien ZFS_EXIT(zfsvfs); 1471174294Sobrien return (error); 1472174294Sobrien } 1473174294Sobrien } 1474174294Sobrientop: 1475174294Sobrien *vpp = NULL; 1476174294Sobrien 1477174294Sobrien if ((vap->va_mode & S_ISVTX) && secpolicy_vnode_stky_modify(cr)) 1478174294Sobrien vap->va_mode &= ~S_ISVTX; 1479174294Sobrien 1480174294Sobrien if (*name == '\0') { 1481174294Sobrien /* 1482174294Sobrien * Null component name refers to the directory itself. 1483174294Sobrien */ 1484174294Sobrien VN_HOLD(dvp); 1485174294Sobrien zp = dzp; 1486174294Sobrien dl = NULL; 1487174294Sobrien error = 0; 1488174294Sobrien } else { 1489174294Sobrien /* possible VN_HOLD(zp) */ 1490174294Sobrien int zflg = 0; 1491174294Sobrien 1492174294Sobrien if (flag & FIGNORECASE) 1493174294Sobrien zflg |= ZCILOOK; 1494174294Sobrien 1495174294Sobrien error = zfs_dirent_lock(&dl, dzp, name, &zp, zflg, 1496174294Sobrien NULL, NULL); 1497174294Sobrien if (error) { 1498174294Sobrien if (strcmp(name, "..") == 0) 1499174294Sobrien error = EISDIR; 1500174294Sobrien ZFS_EXIT(zfsvfs); 1501174294Sobrien return (error); 1502174294Sobrien } 1503174294Sobrien } 1504174294Sobrien if (zp == NULL) { 1505174294Sobrien uint64_t txtype; 1506174294Sobrien 1507174294Sobrien /* 1508174294Sobrien * Create a new file object and update the directory 1509174294Sobrien * to reference it. 1510174294Sobrien */ 1511174294Sobrien if (error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr)) { 1512174294Sobrien goto out; 1513174294Sobrien } 1514174294Sobrien 1515174294Sobrien /* 1516174294Sobrien * We only support the creation of regular files in 1517174294Sobrien * extended attribute directories. 1518174294Sobrien */ 1519174294Sobrien if ((dzp->z_phys->zp_flags & ZFS_XATTR) && 1520174294Sobrien (vap->va_type != VREG)) { 1521174294Sobrien error = EINVAL; 1522174294Sobrien goto out; 1523174294Sobrien } 1524174294Sobrien 1525174294Sobrien 1526174294Sobrien if ((error = zfs_acl_ids_create(dzp, 0, vap, cr, vsecp, 1527174294Sobrien &acl_ids)) != 0) 1528174294Sobrien goto out; 1529174294Sobrien if (zfs_acl_ids_overquota(zfsvfs, &acl_ids)) { 1530174294Sobrien zfs_acl_ids_free(&acl_ids); 1531174294Sobrien error = EDQUOT; 1532174294Sobrien goto out; 1533174294Sobrien } 1534174294Sobrien 1535174294Sobrien tx = dmu_tx_create(os); 1536174294Sobrien dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT); 1537174294Sobrien fuid_dirtied = zfsvfs->z_fuid_dirty; 1538174294Sobrien if (fuid_dirtied) 1539174294Sobrien zfs_fuid_txhold(zfsvfs, tx); 1540174294Sobrien dmu_tx_hold_bonus(tx, dzp->z_id); 1541174294Sobrien dmu_tx_hold_zap(tx, dzp->z_id, TRUE, name); 1542174294Sobrien if (acl_ids.z_aclp->z_acl_bytes > ZFS_ACE_SPACE) { 1543174294Sobrien dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 1544174294Sobrien 0, SPA_MAXBLOCKSIZE); 1545174294Sobrien } 1546174294Sobrien error = dmu_tx_assign(tx, TXG_NOWAIT); 1547174294Sobrien if (error) { 1548174294Sobrien zfs_acl_ids_free(&acl_ids); 1549174294Sobrien zfs_dirent_unlock(dl); 1550174294Sobrien if (error == ERESTART) { 1551174294Sobrien dmu_tx_wait(tx); 1552174294Sobrien dmu_tx_abort(tx); 1553174294Sobrien goto top; 1554174294Sobrien } 1555174294Sobrien dmu_tx_abort(tx); 1556174294Sobrien ZFS_EXIT(zfsvfs); 1557174294Sobrien return (error); 1558174294Sobrien } 1559174294Sobrien zfs_mknode(dzp, vap, tx, cr, 0, &zp, 0, &acl_ids); 1560174294Sobrien 1561174294Sobrien if (fuid_dirtied) 1562174294Sobrien zfs_fuid_sync(zfsvfs, tx); 1563174294Sobrien 1564174294Sobrien (void) zfs_link_create(dl, zp, tx, ZNEW); 1565174294Sobrien 1566174294Sobrien txtype = zfs_log_create_txtype(Z_FILE, vsecp, vap); 1567174294Sobrien if (flag & FIGNORECASE) 1568174294Sobrien txtype |= TX_CI; 1569174294Sobrien zfs_log_create(zilog, tx, txtype, dzp, zp, name, 1570174294Sobrien vsecp, acl_ids.z_fuidp, vap); 1571174294Sobrien zfs_acl_ids_free(&acl_ids); 1572174294Sobrien dmu_tx_commit(tx); 1573174294Sobrien } else { 1574174294Sobrien int aflags = (flag & FAPPEND) ? V_APPEND : 0; 1575174294Sobrien 1576174294Sobrien /* 1577174294Sobrien * A directory entry already exists for this name. 1578174294Sobrien */ 1579174294Sobrien /* 1580174294Sobrien * Can't truncate an existing file if in exclusive mode. 1581174294Sobrien */ 1582174294Sobrien if (excl == EXCL) { 1583174294Sobrien error = EEXIST; 1584174294Sobrien goto out; 1585174294Sobrien } 1586174294Sobrien /* 1587174294Sobrien * Can't open a directory for writing. 1588174294Sobrien */ 1589174294Sobrien if ((ZTOV(zp)->v_type == VDIR) && (mode & S_IWRITE)) { 1590174294Sobrien error = EISDIR; 1591174294Sobrien goto out; 1592174294Sobrien } 1593174294Sobrien /* 1594174294Sobrien * Verify requested access to file. 1595174294Sobrien */ 1596174294Sobrien if (mode && (error = zfs_zaccess_rwx(zp, mode, aflags, cr))) { 1597174294Sobrien goto out; 1598174294Sobrien } 1599174294Sobrien 1600174294Sobrien mutex_enter(&dzp->z_lock); 1601174294Sobrien dzp->z_seq++; 1602174294Sobrien mutex_exit(&dzp->z_lock); 1603174294Sobrien 1604174294Sobrien /* 1605174294Sobrien * Truncate regular files if requested. 1606174294Sobrien */ 1607174294Sobrien if ((ZTOV(zp)->v_type == VREG) && 1608174294Sobrien (vap->va_mask & AT_SIZE) && (vap->va_size == 0)) { 1609174294Sobrien /* we can't hold any locks when calling zfs_freesp() */ 1610174294Sobrien zfs_dirent_unlock(dl); 1611174294Sobrien dl = NULL; 1612174294Sobrien error = zfs_freesp(zp, 0, 0, mode, TRUE); 1613174294Sobrien if (error == 0) { 1614174294Sobrien vnevent_create(ZTOV(zp), ct); 1615174294Sobrien } 1616174294Sobrien } 1617174294Sobrien } 1618174294Sobrienout: 1619174294Sobrien if (dl) 1620174294Sobrien zfs_dirent_unlock(dl); 1621174294Sobrien 1622174294Sobrien if (error) { 1623174294Sobrien if (zp) 1624174294Sobrien VN_RELE(ZTOV(zp)); 1625174294Sobrien } else { 1626174294Sobrien *vpp = ZTOV(zp); 1627174294Sobrien error = specvp_check(vpp, cr); 1628174294Sobrien } 1629174294Sobrien 1630174294Sobrien ZFS_EXIT(zfsvfs); 1631174294Sobrien return (error); 1632174294Sobrien} 1633174294Sobrien 1634174294Sobrien/* 1635174294Sobrien * Remove an entry from a directory. 1636174294Sobrien * 1637174294Sobrien * IN: dvp - vnode of directory to remove entry from. 1638174294Sobrien * name - name of entry to remove. 1639174294Sobrien * cr - credentials of caller. 1640174294Sobrien * ct - caller context 1641174294Sobrien * flags - case flags 1642174294Sobrien * 1643174294Sobrien * RETURN: 0 if success 1644174294Sobrien * error code if failure 1645174294Sobrien * 1646174294Sobrien * Timestamps: 1647174294Sobrien * dvp - ctime|mtime 1648174294Sobrien * vp - ctime (if nlink > 0) 1649174294Sobrien */ 1650174294Sobrien/*ARGSUSED*/ 1651174294Sobrienstatic int 1652174294Sobrienzfs_remove(vnode_t *dvp, char *name, cred_t *cr, caller_context_t *ct, 1653174294Sobrien int flags) 1654174294Sobrien{ 1655174294Sobrien znode_t *zp, *dzp = VTOZ(dvp); 1656174294Sobrien znode_t *xzp = NULL; 1657174294Sobrien vnode_t *vp; 1658174294Sobrien zfsvfs_t *zfsvfs = dzp->z_zfsvfs; 1659174294Sobrien zilog_t *zilog; 1660174294Sobrien uint64_t acl_obj, xattr_obj; 1661174294Sobrien zfs_dirlock_t *dl; 1662174294Sobrien dmu_tx_t *tx; 1663174294Sobrien boolean_t may_delete_now, delete_now = FALSE; 1664174294Sobrien boolean_t unlinked, toobig = FALSE; 1665174294Sobrien uint64_t txtype; 1666174294Sobrien pathname_t *realnmp = NULL; 1667174294Sobrien pathname_t realnm; 1668174294Sobrien int error; 1669174294Sobrien int zflg = ZEXISTS; 1670174294Sobrien 1671174294Sobrien ZFS_ENTER(zfsvfs); 1672174294Sobrien ZFS_VERIFY_ZP(dzp); 1673174294Sobrien zilog = zfsvfs->z_log; 1674174294Sobrien 1675174294Sobrien if (flags & FIGNORECASE) { 1676174294Sobrien zflg |= ZCILOOK; 1677174294Sobrien pn_alloc(&realnm); 1678174294Sobrien realnmp = &realnm; 1679174294Sobrien } 1680174294Sobrien 1681174294Sobrientop: 1682174294Sobrien /* 1683174294Sobrien * Attempt to lock directory; fail if entry doesn't exist. 1684174294Sobrien */ 1685174294Sobrien if (error = zfs_dirent_lock(&dl, dzp, name, &zp, zflg, 1686174294Sobrien NULL, realnmp)) { 1687174294Sobrien if (realnmp) 1688174294Sobrien pn_free(realnmp); 1689174294Sobrien ZFS_EXIT(zfsvfs); 1690174294Sobrien return (error); 1691174294Sobrien } 1692174294Sobrien 1693174294Sobrien vp = ZTOV(zp); 1694174294Sobrien 1695174294Sobrien if (error = zfs_zaccess_delete(dzp, zp, cr)) { 1696174294Sobrien goto out; 1697174294Sobrien } 1698174294Sobrien 1699174294Sobrien /* 1700174294Sobrien * Need to use rmdir for removing directories. 1701174294Sobrien */ 1702174294Sobrien if (vp->v_type == VDIR) { 1703174294Sobrien error = EPERM; 1704174294Sobrien goto out; 1705174294Sobrien } 1706174294Sobrien 1707174294Sobrien vnevent_remove(vp, dvp, name, ct); 1708174294Sobrien 1709174294Sobrien if (realnmp) 1710174294Sobrien dnlc_remove(dvp, realnmp->pn_buf); 1711174294Sobrien else 1712174294Sobrien dnlc_remove(dvp, name); 1713174294Sobrien 1714174294Sobrien may_delete_now = FALSE; 1715174294Sobrien 1716174294Sobrien /* 1717174294Sobrien * We may delete the znode now, or we may put it in the unlinked set; 1718174294Sobrien * it depends on whether we're the last link, and on whether there are 1719174294Sobrien * other holds on the vnode. So we dmu_tx_hold() the right things to 1720174294Sobrien * allow for either case. 1721174294Sobrien */ 1722174294Sobrien tx = dmu_tx_create(zfsvfs->z_os); 1723174294Sobrien dmu_tx_hold_zap(tx, dzp->z_id, FALSE, name); 1724174294Sobrien dmu_tx_hold_bonus(tx, zp->z_id); 1725174294Sobrien if (may_delete_now) { 1726174294Sobrien toobig = 1727174294Sobrien zp->z_phys->zp_size > zp->z_blksz * DMU_MAX_DELETEBLKCNT; 1728174294Sobrien /* if the file is too big, only hold_free a token amount */ 1729174294Sobrien dmu_tx_hold_free(tx, zp->z_id, 0, 1730174294Sobrien (toobig ? DMU_MAX_ACCESS : DMU_OBJECT_END)); 1731174294Sobrien } 1732174294Sobrien 1733174294Sobrien /* are there any extended attributes? */ 1734174294Sobrien if ((xattr_obj = zp->z_phys->zp_xattr) != 0) { 1735174294Sobrien /* XXX - do we need this if we are deleting? */ 1736174294Sobrien dmu_tx_hold_bonus(tx, xattr_obj); 1737174294Sobrien } 1738174294Sobrien 1739174294Sobrien /* are there any additional acls */ 1740174294Sobrien if ((acl_obj = zp->z_phys->zp_acl.z_acl_extern_obj) != 0 && 1741174294Sobrien may_delete_now) 1742174294Sobrien dmu_tx_hold_free(tx, acl_obj, 0, DMU_OBJECT_END); 1743174294Sobrien 1744174294Sobrien /* charge as an update -- would be nice not to charge at all */ 1745174294Sobrien dmu_tx_hold_zap(tx, zfsvfs->z_unlinkedobj, FALSE, NULL); 1746174294Sobrien 1747174294Sobrien error = dmu_tx_assign(tx, TXG_NOWAIT); 1748174294Sobrien if (error) { 1749174294Sobrien zfs_dirent_unlock(dl); 1750174294Sobrien VN_RELE(vp); 1751174294Sobrien if (error == ERESTART) { 1752174294Sobrien dmu_tx_wait(tx); 1753174294Sobrien dmu_tx_abort(tx); 1754174294Sobrien goto top; 1755174294Sobrien } 1756174294Sobrien if (realnmp) 1757174294Sobrien pn_free(realnmp); 1758174294Sobrien dmu_tx_abort(tx); 1759174294Sobrien ZFS_EXIT(zfsvfs); 1760174294Sobrien return (error); 1761174294Sobrien } 1762174294Sobrien 1763174294Sobrien /* 1764174294Sobrien * Remove the directory entry. 1765174294Sobrien */ 1766174294Sobrien error = zfs_link_destroy(dl, zp, tx, zflg, &unlinked); 1767174294Sobrien 1768174294Sobrien if (error) { 1769174294Sobrien dmu_tx_commit(tx); 1770174294Sobrien goto out; 1771174294Sobrien } 1772174294Sobrien 1773174294Sobrien if (0 && unlinked) { 1774174294Sobrien VI_LOCK(vp); 1775174294Sobrien delete_now = may_delete_now && !toobig && 1776174294Sobrien vp->v_count == 1 && !vn_has_cached_data(vp) && 1777174294Sobrien zp->z_phys->zp_xattr == xattr_obj && 1778174294Sobrien zp->z_phys->zp_acl.z_acl_extern_obj == acl_obj; 1779174294Sobrien VI_UNLOCK(vp); 1780174294Sobrien } 1781174294Sobrien 1782174294Sobrien if (delete_now) { 1783174294Sobrien if (zp->z_phys->zp_xattr) { 1784174294Sobrien error = zfs_zget(zfsvfs, zp->z_phys->zp_xattr, &xzp); 1785174294Sobrien ASSERT3U(error, ==, 0); 1786174294Sobrien ASSERT3U(xzp->z_phys->zp_links, ==, 2); 1787174294Sobrien dmu_buf_will_dirty(xzp->z_dbuf, tx); 1788174294Sobrien mutex_enter(&xzp->z_lock); 1789174294Sobrien xzp->z_unlinked = 1; 1790174294Sobrien xzp->z_phys->zp_links = 0; 1791174294Sobrien mutex_exit(&xzp->z_lock); 1792174294Sobrien zfs_unlinked_add(xzp, tx); 1793174294Sobrien zp->z_phys->zp_xattr = 0; /* probably unnecessary */ 1794174294Sobrien } 1795174294Sobrien mutex_enter(&zp->z_lock); 1796174294Sobrien VI_LOCK(vp); 1797174294Sobrien vp->v_count--; 1798174294Sobrien ASSERT3U(vp->v_count, ==, 0); 1799174294Sobrien VI_UNLOCK(vp); 1800174294Sobrien mutex_exit(&zp->z_lock); 1801174294Sobrien zfs_znode_delete(zp, tx); 1802174294Sobrien } else if (unlinked) { 1803174294Sobrien zfs_unlinked_add(zp, tx); 1804174294Sobrien } 1805174294Sobrien 1806174294Sobrien txtype = TX_REMOVE; 1807174294Sobrien if (flags & FIGNORECASE) 1808174294Sobrien txtype |= TX_CI; 1809174294Sobrien zfs_log_remove(zilog, tx, txtype, dzp, name); 1810174294Sobrien 1811174294Sobrien dmu_tx_commit(tx); 1812174294Sobrienout: 1813174294Sobrien if (realnmp) 1814174294Sobrien pn_free(realnmp); 1815174294Sobrien 1816174294Sobrien zfs_dirent_unlock(dl); 1817174294Sobrien 1818174294Sobrien if (!delete_now) { 1819174294Sobrien VN_RELE(vp); 1820174294Sobrien } else if (xzp) { 1821174294Sobrien /* this rele is delayed to prevent nesting transactions */ 1822174294Sobrien VN_RELE(ZTOV(xzp)); 1823174294Sobrien } 1824174294Sobrien 1825174294Sobrien ZFS_EXIT(zfsvfs); 1826174294Sobrien return (error); 1827174294Sobrien} 1828174294Sobrien 1829174294Sobrien/* 1830174294Sobrien * Create a new directory and insert it into dvp using the name 1831174294Sobrien * provided. Return a pointer to the inserted directory. 1832174294Sobrien * 1833174294Sobrien * IN: dvp - vnode of directory to add subdir to. 1834174294Sobrien * dirname - name of new directory. 1835174294Sobrien * vap - attributes of new directory. 1836174294Sobrien * cr - credentials of caller. 1837174294Sobrien * ct - caller context 1838174294Sobrien * vsecp - ACL to be set 1839174294Sobrien * 1840174294Sobrien * OUT: vpp - vnode of created directory. 1841174294Sobrien * 1842174294Sobrien * RETURN: 0 if success 1843174294Sobrien * error code if failure 1844174294Sobrien * 1845174294Sobrien * Timestamps: 1846174294Sobrien * dvp - ctime|mtime updated 1847174294Sobrien * vp - ctime|mtime|atime updated 1848174294Sobrien */ 1849174294Sobrien/*ARGSUSED*/ 1850174294Sobrienstatic int 1851174294Sobrienzfs_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp, cred_t *cr, 1852174294Sobrien caller_context_t *ct, int flags, vsecattr_t *vsecp) 1853174294Sobrien{ 1854174294Sobrien znode_t *zp, *dzp = VTOZ(dvp); 1855174294Sobrien zfsvfs_t *zfsvfs = dzp->z_zfsvfs; 1856174294Sobrien zilog_t *zilog; 1857174294Sobrien zfs_dirlock_t *dl; 1858174294Sobrien uint64_t txtype; 1859174294Sobrien dmu_tx_t *tx; 1860174294Sobrien int error; 1861174294Sobrien int zf = ZNEW; 1862174294Sobrien ksid_t *ksid; 1863174294Sobrien uid_t uid; 1864174294Sobrien gid_t gid = crgetgid(cr); 1865174294Sobrien zfs_acl_ids_t acl_ids; 1866174294Sobrien boolean_t fuid_dirtied; 1867174294Sobrien 1868174294Sobrien ASSERT(vap->va_type == VDIR); 1869174294Sobrien 1870174294Sobrien /* 1871174294Sobrien * If we have an ephemeral id, ACL, or XVATTR then 1872174294Sobrien * make sure file system is at proper version 1873174294Sobrien */ 1874174294Sobrien 1875174294Sobrien ksid = crgetsid(cr, KSID_OWNER); 1876174294Sobrien if (ksid) 1877174294Sobrien uid = ksid_getid(ksid); 1878174294Sobrien else 1879174294Sobrien uid = crgetuid(cr); 1880174294Sobrien if (zfsvfs->z_use_fuids == B_FALSE && 1881174294Sobrien (vsecp || (vap->va_mask & AT_XVATTR) || IS_EPHEMERAL(crgetuid(cr))|| 1882174294Sobrien IS_EPHEMERAL(crgetgid(cr)))) 1883174294Sobrien return (EINVAL); 1884174294Sobrien 1885174294Sobrien ZFS_ENTER(zfsvfs); 1886174294Sobrien ZFS_VERIFY_ZP(dzp); 1887174294Sobrien zilog = zfsvfs->z_log; 1888174294Sobrien 1889174294Sobrien if (dzp->z_phys->zp_flags & ZFS_XATTR) { 1890174294Sobrien ZFS_EXIT(zfsvfs); 1891174294Sobrien return (EINVAL); 1892174294Sobrien } 1893174294Sobrien 1894174294Sobrien if (zfsvfs->z_utf8 && u8_validate(dirname, 1895174294Sobrien strlen(dirname), NULL, U8_VALIDATE_ENTIRE, &error) < 0) { 1896174294Sobrien ZFS_EXIT(zfsvfs); 1897174294Sobrien return (EILSEQ); 1898174294Sobrien } 1899174294Sobrien if (flags & FIGNORECASE) 1900174294Sobrien zf |= ZCILOOK; 1901174294Sobrien 1902174294Sobrien if (vap->va_mask & AT_XVATTR) 1903174294Sobrien if ((error = secpolicy_xvattr(dvp, (xvattr_t *)vap, 1904174294Sobrien crgetuid(cr), cr, vap->va_type)) != 0) { 1905174294Sobrien ZFS_EXIT(zfsvfs); 1906174294Sobrien return (error); 1907174294Sobrien } 1908174294Sobrien 1909174294Sobrien /* 1910174294Sobrien * First make sure the new directory doesn't exist. 1911174294Sobrien */ 1912174294Sobrientop: 1913174294Sobrien *vpp = NULL; 1914174294Sobrien 1915174294Sobrien if (error = zfs_dirent_lock(&dl, dzp, dirname, &zp, zf, 1916174294Sobrien NULL, NULL)) { 1917174294Sobrien ZFS_EXIT(zfsvfs); 1918174294Sobrien return (error); 1919174294Sobrien } 1920174294Sobrien 1921174294Sobrien if (error = zfs_zaccess(dzp, ACE_ADD_SUBDIRECTORY, 0, B_FALSE, cr)) { 1922174294Sobrien zfs_dirent_unlock(dl); 1923174294Sobrien ZFS_EXIT(zfsvfs); 1924174294Sobrien return (error); 1925174294Sobrien } 1926174294Sobrien 1927174294Sobrien if ((error = zfs_acl_ids_create(dzp, 0, vap, cr, vsecp, 1928174294Sobrien &acl_ids)) != 0) { 1929174294Sobrien zfs_dirent_unlock(dl); 1930174294Sobrien ZFS_EXIT(zfsvfs); 1931174294Sobrien return (error); 1932174294Sobrien } 1933174294Sobrien if (zfs_acl_ids_overquota(zfsvfs, &acl_ids)) { 1934174294Sobrien zfs_acl_ids_free(&acl_ids); 1935174294Sobrien zfs_dirent_unlock(dl); 1936174294Sobrien ZFS_EXIT(zfsvfs); 1937174294Sobrien return (EDQUOT); 1938174294Sobrien } 1939174294Sobrien 1940174294Sobrien /* 1941174294Sobrien * Add a new entry to the directory. 1942174294Sobrien */ 1943174294Sobrien tx = dmu_tx_create(zfsvfs->z_os); 1944174294Sobrien dmu_tx_hold_zap(tx, dzp->z_id, TRUE, dirname); 1945174294Sobrien dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, FALSE, NULL); 1946174294Sobrien fuid_dirtied = zfsvfs->z_fuid_dirty; 1947174294Sobrien if (fuid_dirtied) 1948174294Sobrien zfs_fuid_txhold(zfsvfs, tx); 1949174294Sobrien if (acl_ids.z_aclp->z_acl_bytes > ZFS_ACE_SPACE) 1950174294Sobrien dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 1951174294Sobrien 0, SPA_MAXBLOCKSIZE); 1952174294Sobrien error = dmu_tx_assign(tx, TXG_NOWAIT); 1953174294Sobrien if (error) { 1954174294Sobrien zfs_acl_ids_free(&acl_ids); 1955174294Sobrien zfs_dirent_unlock(dl); 1956174294Sobrien if (error == ERESTART) { 1957174294Sobrien dmu_tx_wait(tx); 1958174294Sobrien dmu_tx_abort(tx); 1959174294Sobrien goto top; 1960174294Sobrien } 1961174294Sobrien dmu_tx_abort(tx); 1962174294Sobrien ZFS_EXIT(zfsvfs); 1963174294Sobrien return (error); 1964174294Sobrien } 1965174294Sobrien 1966174294Sobrien /* 1967174294Sobrien * Create new node. 1968174294Sobrien */ 1969174294Sobrien zfs_mknode(dzp, vap, tx, cr, 0, &zp, 0, &acl_ids); 1970174294Sobrien 1971174294Sobrien if (fuid_dirtied) 1972174294Sobrien zfs_fuid_sync(zfsvfs, tx); 1973174294Sobrien /* 1974174294Sobrien * Now put new name in parent dir. 1975174294Sobrien */ 1976174294Sobrien (void) zfs_link_create(dl, zp, tx, ZNEW); 1977174294Sobrien 1978174294Sobrien *vpp = ZTOV(zp); 1979174294Sobrien 1980174294Sobrien txtype = zfs_log_create_txtype(Z_DIR, vsecp, vap); 1981174294Sobrien if (flags & FIGNORECASE) 1982174294Sobrien txtype |= TX_CI; 1983174294Sobrien zfs_log_create(zilog, tx, txtype, dzp, zp, dirname, vsecp, 1984174294Sobrien acl_ids.z_fuidp, vap); 1985174294Sobrien 1986174294Sobrien zfs_acl_ids_free(&acl_ids); 1987174294Sobrien dmu_tx_commit(tx); 1988174294Sobrien 1989174294Sobrien zfs_dirent_unlock(dl); 1990174294Sobrien 1991174294Sobrien ZFS_EXIT(zfsvfs); 1992174294Sobrien return (0); 1993174294Sobrien} 1994174294Sobrien 1995174294Sobrien/* 1996174294Sobrien * Remove a directory subdir entry. If the current working 1997174294Sobrien * directory is the same as the subdir to be removed, the 1998174294Sobrien * remove will fail. 1999174294Sobrien * 2000174294Sobrien * IN: dvp - vnode of directory to remove from. 2001174294Sobrien * name - name of directory to be removed. 2002174294Sobrien * cwd - vnode of current working directory. 2003174294Sobrien * cr - credentials of caller. 2004174294Sobrien * ct - caller context 2005174294Sobrien * flags - case flags 2006174294Sobrien * 2007174294Sobrien * RETURN: 0 if success 2008174294Sobrien * error code if failure 2009174294Sobrien * 2010174294Sobrien * Timestamps: 2011174294Sobrien * dvp - ctime|mtime updated 2012174294Sobrien */ 2013174294Sobrien/*ARGSUSED*/ 2014174294Sobrienstatic int 2015174294Sobrienzfs_rmdir(vnode_t *dvp, char *name, vnode_t *cwd, cred_t *cr, 2016174294Sobrien caller_context_t *ct, int flags) 2017174294Sobrien{ 2018174294Sobrien znode_t *dzp = VTOZ(dvp); 2019174294Sobrien znode_t *zp; 2020174294Sobrien vnode_t *vp; 2021174294Sobrien zfsvfs_t *zfsvfs = dzp->z_zfsvfs; 2022174294Sobrien zilog_t *zilog; 2023174294Sobrien zfs_dirlock_t *dl; 2024174294Sobrien dmu_tx_t *tx; 2025174294Sobrien int error; 2026174294Sobrien int zflg = ZEXISTS; 2027174294Sobrien 2028174294Sobrien ZFS_ENTER(zfsvfs); 2029174294Sobrien ZFS_VERIFY_ZP(dzp); 2030174294Sobrien zilog = zfsvfs->z_log; 2031174294Sobrien 2032174294Sobrien if (flags & FIGNORECASE) 2033174294Sobrien zflg |= ZCILOOK; 2034174294Sobrientop: 2035174294Sobrien zp = NULL; 2036174294Sobrien 2037174294Sobrien /* 2038174294Sobrien * Attempt to lock directory; fail if entry doesn't exist. 2039174294Sobrien */ 2040174294Sobrien if (error = zfs_dirent_lock(&dl, dzp, name, &zp, zflg, 2041174294Sobrien NULL, NULL)) { 2042174294Sobrien ZFS_EXIT(zfsvfs); 2043174294Sobrien return (error); 2044174294Sobrien } 2045174294Sobrien 2046174294Sobrien vp = ZTOV(zp); 2047174294Sobrien 2048174294Sobrien if (error = zfs_zaccess_delete(dzp, zp, cr)) { 2049174294Sobrien goto out; 2050174294Sobrien } 2051174294Sobrien 2052174294Sobrien if (vp->v_type != VDIR) { 2053174294Sobrien error = ENOTDIR; 2054174294Sobrien goto out; 2055174294Sobrien } 2056174294Sobrien 2057174294Sobrien if (vp == cwd) { 2058174294Sobrien error = EINVAL; 2059174294Sobrien goto out; 2060174294Sobrien } 2061174294Sobrien 2062174294Sobrien vnevent_rmdir(vp, dvp, name, ct); 2063174294Sobrien 2064174294Sobrien /* 2065174294Sobrien * Grab a lock on the directory to make sure that noone is 2066174294Sobrien * trying to add (or lookup) entries while we are removing it. 2067174294Sobrien */ 2068174294Sobrien rw_enter(&zp->z_name_lock, RW_WRITER); 2069174294Sobrien 2070174294Sobrien /* 2071174294Sobrien * Grab a lock on the parent pointer to make sure we play well 2072174294Sobrien * with the treewalk and directory rename code. 2073174294Sobrien */ 2074174294Sobrien rw_enter(&zp->z_parent_lock, RW_WRITER); 2075174294Sobrien 2076174294Sobrien tx = dmu_tx_create(zfsvfs->z_os); 2077174294Sobrien dmu_tx_hold_zap(tx, dzp->z_id, FALSE, name); 2078174294Sobrien dmu_tx_hold_bonus(tx, zp->z_id); 2079174294Sobrien dmu_tx_hold_zap(tx, zfsvfs->z_unlinkedobj, FALSE, NULL); 2080174294Sobrien error = dmu_tx_assign(tx, TXG_NOWAIT); 2081174294Sobrien if (error) { 2082174294Sobrien rw_exit(&zp->z_parent_lock); 2083174294Sobrien rw_exit(&zp->z_name_lock); 2084174294Sobrien zfs_dirent_unlock(dl); 2085174294Sobrien VN_RELE(vp); 2086174294Sobrien if (error == ERESTART) { 2087174294Sobrien dmu_tx_wait(tx); 2088174294Sobrien dmu_tx_abort(tx); 2089174294Sobrien goto top; 2090174294Sobrien } 2091174294Sobrien dmu_tx_abort(tx); 2092174294Sobrien ZFS_EXIT(zfsvfs); 2093174294Sobrien return (error); 2094174294Sobrien } 2095174294Sobrien 2096174294Sobrien#ifdef FREEBSD_NAMECACHE 2097174294Sobrien cache_purge(dvp); 2098174294Sobrien#endif 2099174294Sobrien 2100174294Sobrien error = zfs_link_destroy(dl, zp, tx, zflg, NULL); 2101174294Sobrien 2102174294Sobrien if (error == 0) { 2103174294Sobrien uint64_t txtype = TX_RMDIR; 2104174294Sobrien if (flags & FIGNORECASE) 2105174294Sobrien txtype |= TX_CI; 2106174294Sobrien zfs_log_remove(zilog, tx, txtype, dzp, name); 2107174294Sobrien } 2108174294Sobrien 2109174294Sobrien dmu_tx_commit(tx); 2110174294Sobrien 2111174294Sobrien rw_exit(&zp->z_parent_lock); 2112174294Sobrien rw_exit(&zp->z_name_lock); 2113174294Sobrien#ifdef FREEBSD_NAMECACHE 2114174294Sobrien cache_purge(vp); 2115174294Sobrien#endif 2116174294Sobrienout: 2117174294Sobrien zfs_dirent_unlock(dl); 2118174294Sobrien 2119174294Sobrien VN_RELE(vp); 2120174294Sobrien 2121174294Sobrien ZFS_EXIT(zfsvfs); 2122174294Sobrien return (error); 2123174294Sobrien} 2124174294Sobrien 2125174294Sobrien/* 2126174294Sobrien * Read as many directory entries as will fit into the provided 2127174294Sobrien * buffer from the given directory cursor position (specified in 2128174294Sobrien * the uio structure. 2129174294Sobrien * 2130174294Sobrien * IN: vp - vnode of directory to read. 2131174294Sobrien * uio - structure supplying read location, range info, 2132174294Sobrien * and return buffer. 2133174294Sobrien * cr - credentials of caller. 2134174294Sobrien * ct - caller context 2135174294Sobrien * flags - case flags 2136174294Sobrien * 2137174294Sobrien * OUT: uio - updated offset and range, buffer filled. 2138174294Sobrien * eofp - set to true if end-of-file detected. 2139174294Sobrien * 2140174294Sobrien * RETURN: 0 if success 2141174294Sobrien * error code if failure 2142174294Sobrien * 2143174294Sobrien * Timestamps: 2144174294Sobrien * vp - atime updated 2145174294Sobrien * 2146174294Sobrien * Note that the low 4 bits of the cookie returned by zap is always zero. 2147174294Sobrien * This allows us to use the low range for "special" directory entries: 2148174294Sobrien * We use 0 for '.', and 1 for '..'. If this is the root of the filesystem, 2149174294Sobrien * we use the offset 2 for the '.zfs' directory. 2150174294Sobrien */ 2151174294Sobrien/* ARGSUSED */ 2152174294Sobrienstatic int 2153174294Sobrienzfs_readdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp, int *ncookies, u_long **cookies) 2154174294Sobrien{ 2155174294Sobrien znode_t *zp = VTOZ(vp); 2156174294Sobrien iovec_t *iovp; 2157174294Sobrien edirent_t *eodp; 2158174294Sobrien dirent64_t *odp; 2159174294Sobrien zfsvfs_t *zfsvfs = zp->z_zfsvfs; 2160174294Sobrien objset_t *os; 2161174294Sobrien caddr_t outbuf; 2162174294Sobrien size_t bufsize; 2163174294Sobrien zap_cursor_t zc; 2164174294Sobrien zap_attribute_t zap; 2165174294Sobrien uint_t bytes_wanted; 2166174294Sobrien uint64_t offset; /* must be unsigned; checks for < 1 */ 2167174294Sobrien int local_eof; 2168174294Sobrien int outcount; 2169174294Sobrien int error; 2170174294Sobrien uint8_t prefetch; 2171174294Sobrien boolean_t check_sysattrs; 2172174294Sobrien uint8_t type; 2173174294Sobrien int ncooks; 2174174294Sobrien u_long *cooks = NULL; 2175174294Sobrien int flags = 0; 2176174294Sobrien 2177174294Sobrien ZFS_ENTER(zfsvfs); 2178174294Sobrien ZFS_VERIFY_ZP(zp); 2179174294Sobrien 2180174294Sobrien /* 2181174294Sobrien * If we are not given an eof variable, 2182174294Sobrien * use a local one. 2183174294Sobrien */ 2184174294Sobrien if (eofp == NULL) 2185174294Sobrien eofp = &local_eof; 2186174294Sobrien 2187174294Sobrien /* 2188174294Sobrien * Check for valid iov_len. 2189174294Sobrien */ 2190174294Sobrien if (uio->uio_iov->iov_len <= 0) { 2191174294Sobrien ZFS_EXIT(zfsvfs); 2192174294Sobrien return (EINVAL); 2193174294Sobrien } 2194174294Sobrien 2195174294Sobrien /* 2196174294Sobrien * Quit if directory has been removed (posix) 2197174294Sobrien */ 2198174294Sobrien if ((*eofp = zp->z_unlinked) != 0) { 2199174294Sobrien ZFS_EXIT(zfsvfs); 2200174294Sobrien return (0); 2201174294Sobrien } 2202174294Sobrien 2203174294Sobrien error = 0; 2204174294Sobrien os = zfsvfs->z_os; 2205174294Sobrien offset = uio->uio_loffset; 2206174294Sobrien prefetch = zp->z_zn_prefetch; 2207174294Sobrien 2208174294Sobrien /* 2209174294Sobrien * Initialize the iterator cursor. 2210174294Sobrien */ 2211174294Sobrien if (offset <= 3) { 2212174294Sobrien /* 2213174294Sobrien * Start iteration from the beginning of the directory. 2214174294Sobrien */ 2215174294Sobrien zap_cursor_init(&zc, os, zp->z_id); 2216174294Sobrien } else { 2217174294Sobrien /* 2218174294Sobrien * The offset is a serialized cursor. 2219174294Sobrien */ 2220174294Sobrien zap_cursor_init_serialized(&zc, os, zp->z_id, offset); 2221174294Sobrien } 2222174294Sobrien 2223174294Sobrien /* 2224174294Sobrien * Get space to change directory entries into fs independent format. 2225174294Sobrien */ 2226174294Sobrien iovp = uio->uio_iov; 2227174294Sobrien bytes_wanted = iovp->iov_len; 2228174294Sobrien if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1) { 2229174294Sobrien bufsize = bytes_wanted; 2230174294Sobrien outbuf = kmem_alloc(bufsize, KM_SLEEP); 2231174294Sobrien odp = (struct dirent64 *)outbuf; 2232174294Sobrien } else { 2233174294Sobrien bufsize = bytes_wanted; 2234174294Sobrien odp = (struct dirent64 *)iovp->iov_base; 2235174294Sobrien } 2236174294Sobrien eodp = (struct edirent *)odp; 2237174294Sobrien 2238174294Sobrien if (ncookies != NULL) { 2239174294Sobrien /* 2240174294Sobrien * Minimum entry size is dirent size and 1 byte for a file name. 2241174294Sobrien */ 2242174294Sobrien ncooks = uio->uio_resid / (sizeof(struct dirent) - sizeof(((struct dirent *)NULL)->d_name) + 1); 2243174294Sobrien cooks = malloc(ncooks * sizeof(u_long), M_TEMP, M_WAITOK); 2244174294Sobrien *cookies = cooks; 2245174294Sobrien *ncookies = ncooks; 2246174294Sobrien } 2247174294Sobrien /* 2248174294Sobrien * If this VFS supports the system attribute view interface; and 2249174294Sobrien * we're looking at an extended attribute directory; and we care 2250174294Sobrien * about normalization conflicts on this vfs; then we must check 2251174294Sobrien * for normalization conflicts with the sysattr name space. 2252174294Sobrien */ 2253174294Sobrien#ifdef TODO 2254174294Sobrien check_sysattrs = vfs_has_feature(vp->v_vfsp, VFSFT_SYSATTR_VIEWS) && 2255174294Sobrien (vp->v_flag & V_XATTRDIR) && zfsvfs->z_norm && 2256174294Sobrien (flags & V_RDDIR_ENTFLAGS); 2257174294Sobrien#else 2258174294Sobrien check_sysattrs = 0; 2259174294Sobrien#endif 2260174294Sobrien 2261174294Sobrien /* 2262174294Sobrien * Transform to file-system independent format 2263174294Sobrien */ 2264174294Sobrien outcount = 0; 2265174294Sobrien while (outcount < bytes_wanted) { 2266174294Sobrien ino64_t objnum; 2267174294Sobrien ushort_t reclen; 2268174294Sobrien off64_t *next; 2269174294Sobrien 2270174294Sobrien /* 2271174294Sobrien * Special case `.', `..', and `.zfs'. 2272174294Sobrien */ 2273174294Sobrien if (offset == 0) { 2274174294Sobrien (void) strcpy(zap.za_name, "."); 2275174294Sobrien zap.za_normalization_conflict = 0; 2276174294Sobrien objnum = zp->z_id; 2277174294Sobrien type = DT_DIR; 2278174294Sobrien } else if (offset == 1) { 2279174294Sobrien (void) strcpy(zap.za_name, ".."); 2280174294Sobrien zap.za_normalization_conflict = 0; 2281174294Sobrien objnum = zp->z_phys->zp_parent; 2282174294Sobrien type = DT_DIR; 2283174294Sobrien } else if (offset == 2 && zfs_show_ctldir(zp)) { 2284174294Sobrien (void) strcpy(zap.za_name, ZFS_CTLDIR_NAME); 2285174294Sobrien zap.za_normalization_conflict = 0; 2286174294Sobrien objnum = ZFSCTL_INO_ROOT; 2287174294Sobrien type = DT_DIR; 2288174294Sobrien } else { 2289174294Sobrien /* 2290174294Sobrien * Grab next entry. 2291174294Sobrien */ 2292174294Sobrien if (error = zap_cursor_retrieve(&zc, &zap)) { 2293174294Sobrien if ((*eofp = (error == ENOENT)) != 0) 2294174294Sobrien break; 2295174294Sobrien else 2296174294Sobrien goto update; 2297174294Sobrien } 2298174294Sobrien 2299174294Sobrien if (zap.za_integer_length != 8 || 2300174294Sobrien zap.za_num_integers != 1) { 2301174294Sobrien cmn_err(CE_WARN, "zap_readdir: bad directory " 2302174294Sobrien "entry, obj = %lld, offset = %lld\n", 2303174294Sobrien (u_longlong_t)zp->z_id, 2304174294Sobrien (u_longlong_t)offset); 2305174294Sobrien error = ENXIO; 2306174294Sobrien goto update; 2307174294Sobrien } 2308174294Sobrien 2309174294Sobrien objnum = ZFS_DIRENT_OBJ(zap.za_first_integer); 2310174294Sobrien /* 2311174294Sobrien * MacOS X can extract the object type here such as: 2312174294Sobrien * uint8_t type = ZFS_DIRENT_TYPE(zap.za_first_integer); 2313174294Sobrien */ 2314174294Sobrien type = ZFS_DIRENT_TYPE(zap.za_first_integer); 2315174294Sobrien 2316174294Sobrien if (check_sysattrs && !zap.za_normalization_conflict) { 2317174294Sobrien#ifdef TODO 2318174294Sobrien zap.za_normalization_conflict = 2319174294Sobrien xattr_sysattr_casechk(zap.za_name); 2320174294Sobrien#else 2321174294Sobrien panic("%s:%u: TODO", __func__, __LINE__); 2322174294Sobrien#endif 2323174294Sobrien } 2324174294Sobrien } 2325174294Sobrien 2326174294Sobrien if (flags & V_RDDIR_ACCFILTER) { 2327174294Sobrien /* 2328174294Sobrien * If we have no access at all, don't include 2329174294Sobrien * this entry in the returned information 2330174294Sobrien */ 2331174294Sobrien znode_t *ezp; 2332174294Sobrien if (zfs_zget(zp->z_zfsvfs, objnum, &ezp) != 0) 2333174294Sobrien goto skip_entry; 2334174294Sobrien if (!zfs_has_access(ezp, cr)) { 2335174294Sobrien VN_RELE(ZTOV(ezp)); 2336174294Sobrien goto skip_entry; 2337174294Sobrien } 2338174294Sobrien VN_RELE(ZTOV(ezp)); 2339174294Sobrien } 2340174294Sobrien 2341174294Sobrien if (flags & V_RDDIR_ENTFLAGS) 2342174294Sobrien reclen = EDIRENT_RECLEN(strlen(zap.za_name)); 2343174294Sobrien else 2344174294Sobrien reclen = DIRENT64_RECLEN(strlen(zap.za_name)); 2345174294Sobrien 2346174294Sobrien /* 2347174294Sobrien * Will this entry fit in the buffer? 2348174294Sobrien */ 2349174294Sobrien if (outcount + reclen > bufsize) { 2350174294Sobrien /* 2351174294Sobrien * Did we manage to fit anything in the buffer? 2352174294Sobrien */ 2353174294Sobrien if (!outcount) { 2354174294Sobrien error = EINVAL; 2355174294Sobrien goto update; 2356174294Sobrien } 2357174294Sobrien break; 2358174294Sobrien } 2359174294Sobrien if (flags & V_RDDIR_ENTFLAGS) { 2360174294Sobrien /* 2361174294Sobrien * Add extended flag entry: 2362174294Sobrien */ 2363174294Sobrien eodp->ed_ino = objnum; 2364174294Sobrien eodp->ed_reclen = reclen; 2365174294Sobrien /* NOTE: ed_off is the offset for the *next* entry */ 2366174294Sobrien next = &(eodp->ed_off); 2367174294Sobrien eodp->ed_eflags = zap.za_normalization_conflict ? 2368174294Sobrien ED_CASE_CONFLICT : 0; 2369174294Sobrien (void) strncpy(eodp->ed_name, zap.za_name, 2370174294Sobrien EDIRENT_NAMELEN(reclen)); 2371174294Sobrien eodp = (edirent_t *)((intptr_t)eodp + reclen); 2372174294Sobrien } else { 2373174294Sobrien /* 2374174294Sobrien * Add normal entry: 2375174294Sobrien */ 2376174294Sobrien odp->d_ino = objnum; 2377174294Sobrien odp->d_reclen = reclen; 2378174294Sobrien odp->d_namlen = strlen(zap.za_name); 2379174294Sobrien (void) strlcpy(odp->d_name, zap.za_name, odp->d_namlen + 1); 2380174294Sobrien odp->d_type = type; 2381174294Sobrien odp = (dirent64_t *)((intptr_t)odp + reclen); 2382174294Sobrien } 2383174294Sobrien outcount += reclen; 2384174294Sobrien 2385174294Sobrien ASSERT(outcount <= bufsize); 2386174294Sobrien 2387174294Sobrien /* Prefetch znode */ 2388174294Sobrien if (prefetch) 2389174294Sobrien dmu_prefetch(os, objnum, 0, 0); 2390174294Sobrien 2391174294Sobrien skip_entry: 2392174294Sobrien /* 2393174294Sobrien * Move to the next entry, fill in the previous offset. 2394174294Sobrien */ 2395174294Sobrien if (offset > 2 || (offset == 2 && !zfs_show_ctldir(zp))) { 2396174294Sobrien zap_cursor_advance(&zc); 2397174294Sobrien offset = zap_cursor_serialize(&zc); 2398174294Sobrien } else { 2399174294Sobrien offset += 1; 2400174294Sobrien } 2401174294Sobrien 2402174294Sobrien if (cooks != NULL) { 2403174294Sobrien *cooks++ = offset; 2404174294Sobrien ncooks--; 2405174294Sobrien KASSERT(ncooks >= 0, ("ncookies=%d", ncooks)); 2406174294Sobrien } 2407174294Sobrien } 2408174294Sobrien zp->z_zn_prefetch = B_FALSE; /* a lookup will re-enable pre-fetching */ 2409174294Sobrien 2410174294Sobrien /* Subtract unused cookies */ 2411174294Sobrien if (ncookies != NULL) 2412174294Sobrien *ncookies -= ncooks; 2413174294Sobrien 2414174294Sobrien if (uio->uio_segflg == UIO_SYSSPACE && uio->uio_iovcnt == 1) { 2415174294Sobrien iovp->iov_base += outcount; 2416174294Sobrien iovp->iov_len -= outcount; 2417174294Sobrien uio->uio_resid -= outcount; 2418174294Sobrien } else if (error = uiomove(outbuf, (long)outcount, UIO_READ, uio)) { 2419174294Sobrien /* 2420174294Sobrien * Reset the pointer. 2421174294Sobrien */ 2422174294Sobrien offset = uio->uio_loffset; 2423174294Sobrien } 2424174294Sobrien 2425174294Sobrienupdate: 2426174294Sobrien zap_cursor_fini(&zc); 2427174294Sobrien if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1) 2428174294Sobrien kmem_free(outbuf, bufsize); 2429174294Sobrien 2430174294Sobrien if (error == ENOENT) 2431174294Sobrien error = 0; 2432174294Sobrien 2433174294Sobrien ZFS_ACCESSTIME_STAMP(zfsvfs, zp); 2434174294Sobrien 2435174294Sobrien uio->uio_loffset = offset; 2436174294Sobrien ZFS_EXIT(zfsvfs); 2437174294Sobrien if (error != 0 && cookies != NULL) { 2438174294Sobrien free(*cookies, M_TEMP); 2439174294Sobrien *cookies = NULL; 2440174294Sobrien *ncookies = 0; 2441174294Sobrien } 2442174294Sobrien return (error); 2443174294Sobrien} 2444174294Sobrien 2445174294Sobrienulong_t zfs_fsync_sync_cnt = 4; 2446174294Sobrien 2447174294Sobrienstatic int 2448174294Sobrienzfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct) 2449174294Sobrien{ 2450174294Sobrien znode_t *zp = VTOZ(vp); 2451174294Sobrien zfsvfs_t *zfsvfs = zp->z_zfsvfs; 2452174294Sobrien 2453174294Sobrien (void) tsd_set(zfs_fsyncer_key, (void *)zfs_fsync_sync_cnt); 2454174294Sobrien 2455174294Sobrien ZFS_ENTER(zfsvfs); 2456174294Sobrien ZFS_VERIFY_ZP(zp); 2457174294Sobrien zil_commit(zfsvfs->z_log, zp->z_last_itx, zp->z_id); 2458174294Sobrien ZFS_EXIT(zfsvfs); 2459174294Sobrien return (0); 2460174294Sobrien} 2461174294Sobrien 2462174294Sobrien 2463174294Sobrien/* 2464174294Sobrien * Get the requested file attributes and place them in the provided 2465174294Sobrien * vattr structure. 2466174294Sobrien * 2467174294Sobrien * IN: vp - vnode of file. 2468174294Sobrien * vap - va_mask identifies requested attributes. 2469174294Sobrien * If AT_XVATTR set, then optional attrs are requested 2470174294Sobrien * flags - ATTR_NOACLCHECK (CIFS server context) 2471174294Sobrien * cr - credentials of caller. 2472174294Sobrien * ct - caller context 2473174294Sobrien * 2474174294Sobrien * OUT: vap - attribute values. 2475174294Sobrien * 2476174294Sobrien * RETURN: 0 (always succeeds) 2477174294Sobrien */ 2478174294Sobrien/* ARGSUSED */ 2479174294Sobrienstatic int 2480174294Sobrienzfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, 2481174294Sobrien caller_context_t *ct) 2482174294Sobrien{ 2483174294Sobrien znode_t *zp = VTOZ(vp); 2484174294Sobrien zfsvfs_t *zfsvfs = zp->z_zfsvfs; 2485174294Sobrien znode_phys_t *pzp; 2486174294Sobrien int error = 0; 2487174294Sobrien uint32_t blksize; 2488174294Sobrien u_longlong_t nblocks; 2489174294Sobrien uint64_t links; 2490174294Sobrien xvattr_t *xvap = (xvattr_t *)vap; /* vap may be an xvattr_t * */ 2491174294Sobrien xoptattr_t *xoap = NULL; 2492174294Sobrien boolean_t skipaclchk = (flags & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE; 2493174294Sobrien 2494174294Sobrien ZFS_ENTER(zfsvfs); 2495174294Sobrien ZFS_VERIFY_ZP(zp); 2496174294Sobrien pzp = zp->z_phys; 2497174294Sobrien 2498174294Sobrien /* 2499174294Sobrien * If ACL is trivial don't bother looking for ACE_READ_ATTRIBUTES. 2500174294Sobrien * Also, if we are the owner don't bother, since owner should 2501174294Sobrien * always be allowed to read basic attributes of file. 2502174294Sobrien */ 2503174294Sobrien if (!(pzp->zp_flags & ZFS_ACL_TRIVIAL) && 2504174294Sobrien (pzp->zp_uid != crgetuid(cr))) { 2505174294Sobrien if (error = zfs_zaccess(zp, ACE_READ_ATTRIBUTES, 0, 2506174294Sobrien skipaclchk, cr)) { 2507174294Sobrien ZFS_EXIT(zfsvfs); 2508174294Sobrien return (error); 2509174294Sobrien } 2510174294Sobrien } 2511174294Sobrien 2512174294Sobrien /* 2513174294Sobrien * Return all attributes. It's cheaper to provide the answer 2514174294Sobrien * than to determine whether we were asked the question. 2515174294Sobrien */ 2516174294Sobrien 2517174294Sobrien mutex_enter(&zp->z_lock); 2518174294Sobrien vap->va_type = IFTOVT(pzp->zp_mode); 2519174294Sobrien vap->va_mode = pzp->zp_mode & ~S_IFMT; 2520174294Sobrien zfs_fuid_map_ids(zp, cr, &vap->va_uid, &vap->va_gid); 2521174294Sobrien// vap->va_fsid = zp->z_zfsvfs->z_vfs->vfs_dev; 2522174294Sobrien vap->va_nodeid = zp->z_id; 2523174294Sobrien if ((vp->v_flag & VROOT) && zfs_show_ctldir(zp)) 2524174294Sobrien links = pzp->zp_links + 1; 2525174294Sobrien else 2526174294Sobrien links = pzp->zp_links; 2527174294Sobrien vap->va_nlink = MIN(links, UINT32_MAX); /* nlink_t limit! */ 2528174294Sobrien vap->va_size = pzp->zp_size; 2529174294Sobrien vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 2530174294Sobrien vap->va_rdev = zfs_cmpldev(pzp->zp_rdev); 2531174294Sobrien vap->va_seq = zp->z_seq; 2532174294Sobrien vap->va_flags = 0; /* FreeBSD: Reset chflags(2) flags. */ 2533174294Sobrien 2534174294Sobrien /* 2535174294Sobrien * Add in any requested optional attributes and the create time. 2536174294Sobrien * Also set the corresponding bits in the returned attribute bitmap. 2537174294Sobrien */ 2538174294Sobrien if ((xoap = xva_getxoptattr(xvap)) != NULL && zfsvfs->z_use_fuids) { 2539174294Sobrien if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE)) { 2540174294Sobrien xoap->xoa_archive = 2541174294Sobrien ((pzp->zp_flags & ZFS_ARCHIVE) != 0); 2542174294Sobrien XVA_SET_RTN(xvap, XAT_ARCHIVE); 2543174294Sobrien } 2544174294Sobrien 2545174294Sobrien if (XVA_ISSET_REQ(xvap, XAT_READONLY)) { 2546174294Sobrien xoap->xoa_readonly = 2547174294Sobrien ((pzp->zp_flags & ZFS_READONLY) != 0); 2548174294Sobrien XVA_SET_RTN(xvap, XAT_READONLY); 2549174294Sobrien } 2550174294Sobrien 2551174294Sobrien if (XVA_ISSET_REQ(xvap, XAT_SYSTEM)) { 2552174294Sobrien xoap->xoa_system = 2553174294Sobrien ((pzp->zp_flags & ZFS_SYSTEM) != 0); 2554174294Sobrien XVA_SET_RTN(xvap, XAT_SYSTEM); 2555174294Sobrien } 2556174294Sobrien 2557174294Sobrien if (XVA_ISSET_REQ(xvap, XAT_HIDDEN)) { 2558174294Sobrien xoap->xoa_hidden = 2559174294Sobrien ((pzp->zp_flags & ZFS_HIDDEN) != 0); 2560174294Sobrien XVA_SET_RTN(xvap, XAT_HIDDEN); 2561174294Sobrien } 2562174294Sobrien 2563174294Sobrien if (XVA_ISSET_REQ(xvap, XAT_NOUNLINK)) { 2564174294Sobrien xoap->xoa_nounlink = 2565174294Sobrien ((pzp->zp_flags & ZFS_NOUNLINK) != 0); 2566174294Sobrien XVA_SET_RTN(xvap, XAT_NOUNLINK); 2567174294Sobrien } 2568174294Sobrien 2569174294Sobrien if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE)) { 2570174294Sobrien xoap->xoa_immutable = 2571174294Sobrien ((pzp->zp_flags & ZFS_IMMUTABLE) != 0); 2572174294Sobrien XVA_SET_RTN(xvap, XAT_IMMUTABLE); 2573174294Sobrien } 2574174294Sobrien 2575174294Sobrien if (XVA_ISSET_REQ(xvap, XAT_APPENDONLY)) { 2576174294Sobrien xoap->xoa_appendonly = 2577174294Sobrien ((pzp->zp_flags & ZFS_APPENDONLY) != 0); 2578174294Sobrien XVA_SET_RTN(xvap, XAT_APPENDONLY); 2579174294Sobrien } 2580174294Sobrien 2581174294Sobrien if (XVA_ISSET_REQ(xvap, XAT_NODUMP)) { 2582174294Sobrien xoap->xoa_nodump = 2583174294Sobrien ((pzp->zp_flags & ZFS_NODUMP) != 0); 2584174294Sobrien XVA_SET_RTN(xvap, XAT_NODUMP); 2585174294Sobrien } 2586174294Sobrien 2587174294Sobrien if (XVA_ISSET_REQ(xvap, XAT_OPAQUE)) { 2588174294Sobrien xoap->xoa_opaque = 2589174294Sobrien ((pzp->zp_flags & ZFS_OPAQUE) != 0); 2590174294Sobrien XVA_SET_RTN(xvap, XAT_OPAQUE); 2591174294Sobrien } 2592174294Sobrien 2593174294Sobrien if (XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED)) { 2594131702Smbr xoap->xoa_av_quarantined = 2595131702Smbr ((pzp->zp_flags & ZFS_AV_QUARANTINED) != 0); 2596131702Smbr XVA_SET_RTN(xvap, XAT_AV_QUARANTINED); 2597131702Smbr } 2598131702Smbr 2599131702Smbr if (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED)) { 2600131702Smbr xoap->xoa_av_modified = 2601131702Smbr ((pzp->zp_flags & ZFS_AV_MODIFIED) != 0); 2602131702Smbr XVA_SET_RTN(xvap, XAT_AV_MODIFIED); 2603131702Smbr } 2604131702Smbr 2605131702Smbr if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP) && 2606131702Smbr vp->v_type == VREG && 2607131702Smbr (pzp->zp_flags & ZFS_BONUS_SCANSTAMP)) { 2608131702Smbr size_t len; 2609131702Smbr dmu_object_info_t doi; 2610131702Smbr 2611131702Smbr /* 2612131702Smbr * Only VREG files have anti-virus scanstamps, so we 2613131702Smbr * won't conflict with symlinks in the bonus buffer. 2614131702Smbr */ 2615131702Smbr dmu_object_info_from_db(zp->z_dbuf, &doi); 2616131702Smbr len = sizeof (xoap->xoa_av_scanstamp) + 2617131702Smbr sizeof (znode_phys_t); 2618131702Smbr if (len <= doi.doi_bonus_size) { 2619131702Smbr /* 2620131702Smbr * pzp points to the start of the 2621131702Smbr * znode_phys_t. pzp + 1 points to the 2622131702Smbr * first byte after the znode_phys_t. 2623131702Smbr */ 2624131702Smbr (void) memcpy(xoap->xoa_av_scanstamp, 2625131702Smbr pzp + 1, 2626131702Smbr sizeof (xoap->xoa_av_scanstamp)); 2627131702Smbr XVA_SET_RTN(xvap, XAT_AV_SCANSTAMP); 2628131702Smbr } 2629131702Smbr } 2630174294Sobrien 2631174294Sobrien if (XVA_ISSET_REQ(xvap, XAT_CREATETIME)) { 2632174294Sobrien ZFS_TIME_DECODE(&xoap->xoa_createtime, pzp->zp_crtime); 2633174294Sobrien XVA_SET_RTN(xvap, XAT_CREATETIME); 2634131702Smbr } 2635131702Smbr } 2636131702Smbr 2637174294Sobrien ZFS_TIME_DECODE(&vap->va_atime, pzp->zp_atime); 2638174294Sobrien ZFS_TIME_DECODE(&vap->va_mtime, pzp->zp_mtime); 2639131702Smbr ZFS_TIME_DECODE(&vap->va_ctime, pzp->zp_ctime); 2640131702Smbr ZFS_TIME_DECODE(&vap->va_birthtime, pzp->zp_crtime); 2641131702Smbr 2642131702Smbr mutex_exit(&zp->z_lock); 2643131702Smbr 2644131702Smbr dmu_object_size_from_db(zp->z_dbuf, &blksize, &nblocks); 2645131702Smbr vap->va_blksize = blksize; 2646131702Smbr vap->va_bytes = nblocks << 9; /* nblocks * 512 */ 2647131702Smbr 2648131702Smbr if (zp->z_blksz == 0) { 2649174294Sobrien /* 2650131702Smbr * Block size hasn't been set; suggest maximal I/O transfers. 2651131702Smbr */ 2652131702Smbr vap->va_blksize = zfsvfs->z_max_blksz; 2653174294Sobrien } 2654174294Sobrien 2655174294Sobrien ZFS_EXIT(zfsvfs); 2656174294Sobrien return (0); 2657174294Sobrien} 2658174294Sobrien 2659174294Sobrien/* 2660174294Sobrien * Set the file attributes to the values contained in the 2661174294Sobrien * vattr structure. 2662174294Sobrien * 2663174294Sobrien * IN: vp - vnode of file to be modified. 2664174294Sobrien * vap - new attribute values. 2665174294Sobrien * If AT_XVATTR set, then optional attrs are being set 2666174294Sobrien * flags - ATTR_UTIME set if non-default time values provided. 2667174294Sobrien * - ATTR_NOACLCHECK (CIFS context only). 2668174294Sobrien * cr - credentials of caller. 2669174294Sobrien * ct - caller context 2670174294Sobrien * 2671174294Sobrien * RETURN: 0 if success 2672174294Sobrien * error code if failure 2673174294Sobrien * 2674174294Sobrien * Timestamps: 2675174294Sobrien * vp - ctime updated, mtime updated if size changed. 2676174294Sobrien */ 2677174294Sobrien/* ARGSUSED */ 2678174294Sobrienstatic int 2679174294Sobrienzfs_setattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, 2680174294Sobrien caller_context_t *ct) 2681174294Sobrien{ 2682174294Sobrien znode_t *zp = VTOZ(vp); 2683174294Sobrien znode_phys_t *pzp; 2684174294Sobrien zfsvfs_t *zfsvfs = zp->z_zfsvfs; 2685174294Sobrien zilog_t *zilog; 2686174294Sobrien dmu_tx_t *tx; 2687174294Sobrien vattr_t oldva; 2688174294Sobrien xvattr_t tmpxvattr; 2689174294Sobrien uint_t mask = vap->va_mask; 2690174294Sobrien uint_t saved_mask; 2691174294Sobrien uint64_t saved_mode; 2692174294Sobrien int trim_mask = 0; 2693174294Sobrien uint64_t new_mode; 2694174294Sobrien uint64_t new_uid, new_gid; 2695174294Sobrien znode_t *attrzp; 2696174294Sobrien int need_policy = FALSE; 2697174294Sobrien int err; 2698174294Sobrien zfs_fuid_info_t *fuidp = NULL; 2699174294Sobrien xvattr_t *xvap = (xvattr_t *)vap; /* vap may be an xvattr_t * */ 2700174294Sobrien xoptattr_t *xoap; 2701174294Sobrien zfs_acl_t *aclp = NULL; 2702174294Sobrien boolean_t skipaclchk = (flags & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE; 2703174294Sobrien boolean_t fuid_dirtied = B_FALSE; 2704174294Sobrien 2705174294Sobrien if (mask == 0) 2706174294Sobrien return (0); 2707174294Sobrien 2708174294Sobrien if (mask & AT_NOSET) 2709174294Sobrien return (EINVAL); 2710174294Sobrien 2711174294Sobrien ZFS_ENTER(zfsvfs); 2712174294Sobrien ZFS_VERIFY_ZP(zp); 2713174294Sobrien 2714174294Sobrien pzp = zp->z_phys; 2715174294Sobrien zilog = zfsvfs->z_log; 2716174294Sobrien 2717174294Sobrien /* 2718174294Sobrien * Make sure that if we have ephemeral uid/gid or xvattr specified 2719174294Sobrien * that file system is at proper version level 2720174294Sobrien */ 2721174294Sobrien 2722174294Sobrien if (zfsvfs->z_use_fuids == B_FALSE && 2723174294Sobrien (((mask & AT_UID) && IS_EPHEMERAL(vap->va_uid)) || 2724174294Sobrien ((mask & AT_GID) && IS_EPHEMERAL(vap->va_gid)) || 2725174294Sobrien (mask & AT_XVATTR))) { 2726174294Sobrien ZFS_EXIT(zfsvfs); 2727174294Sobrien return (EINVAL); 2728174294Sobrien } 2729174294Sobrien 2730174294Sobrien if (mask & AT_SIZE && vp->v_type == VDIR) { 2731174294Sobrien ZFS_EXIT(zfsvfs); 2732174294Sobrien return (EISDIR); 2733174294Sobrien } 2734174294Sobrien 2735174294Sobrien if (mask & AT_SIZE && vp->v_type != VREG && vp->v_type != VFIFO) { 2736174294Sobrien ZFS_EXIT(zfsvfs); 2737174294Sobrien return (EINVAL); 2738174294Sobrien } 2739174294Sobrien 2740131702Smbr /* 2741131702Smbr * If this is an xvattr_t, then get a pointer to the structure of 2742174294Sobrien * optional attributes. If this is NULL, then we have a vattr_t. 2743131702Smbr */ 2744174294Sobrien xoap = xva_getxoptattr(xvap); 2745174294Sobrien 2746174294Sobrien xva_init(&tmpxvattr); 2747174294Sobrien 2748174294Sobrien /* 2749174294Sobrien * Immutable files can only alter immutable bit and atime 2750174294Sobrien */ 2751174294Sobrien if ((pzp->zp_flags & ZFS_IMMUTABLE) && 2752174294Sobrien ((mask & (AT_SIZE|AT_UID|AT_GID|AT_MTIME|AT_MODE)) || 2753174294Sobrien ((mask & AT_XVATTR) && XVA_ISSET_REQ(xvap, XAT_CREATETIME)))) { 2754174294Sobrien ZFS_EXIT(zfsvfs); 2755174294Sobrien return (EPERM); 2756174294Sobrien } 2757174294Sobrien 2758174294Sobrien if ((mask & AT_SIZE) && (pzp->zp_flags & ZFS_READONLY)) { 2759174294Sobrien ZFS_EXIT(zfsvfs); 2760174294Sobrien return (EPERM); 2761174294Sobrien } 2762174294Sobrien 2763174294Sobrien /* 2764174294Sobrien * Verify timestamps doesn't overflow 32 bits. 2765174294Sobrien * ZFS can handle large timestamps, but 32bit syscalls can't 2766174294Sobrien * handle times greater than 2039. This check should be removed 2767174294Sobrien * once large timestamps are fully supported. 2768174294Sobrien */ 2769174294Sobrien if (mask & (AT_ATIME | AT_MTIME)) { 2770174294Sobrien if (((mask & AT_ATIME) && TIMESPEC_OVERFLOW(&vap->va_atime)) || 2771174294Sobrien ((mask & AT_MTIME) && TIMESPEC_OVERFLOW(&vap->va_mtime))) { 2772174294Sobrien ZFS_EXIT(zfsvfs); 2773174294Sobrien return (EOVERFLOW); 2774174294Sobrien } 2775174294Sobrien } 2776174294Sobrien 2777174294Sobrientop: 2778174294Sobrien attrzp = NULL; 2779174294Sobrien 2780174294Sobrien /* Can this be moved to before the top label? */ 2781174294Sobrien if (zfsvfs->z_vfs->vfs_flag & VFS_RDONLY) { 2782174294Sobrien ZFS_EXIT(zfsvfs); 2783174294Sobrien return (EROFS); 2784174294Sobrien } 2785174294Sobrien 2786174294Sobrien /* 2787174294Sobrien * First validate permissions 2788174294Sobrien */ 2789174294Sobrien 2790174294Sobrien if (mask & AT_SIZE) { 2791174294Sobrien err = zfs_zaccess(zp, ACE_WRITE_DATA, 0, skipaclchk, cr); 2792174294Sobrien if (err) { 2793174294Sobrien ZFS_EXIT(zfsvfs); 2794174294Sobrien return (err); 2795174294Sobrien } 2796174294Sobrien /* 2797174294Sobrien * XXX - Note, we are not providing any open 2798174294Sobrien * mode flags here (like FNDELAY), so we may 2799174294Sobrien * block if there are locks present... this 2800174294Sobrien * should be addressed in openat(). 2801174294Sobrien */ 2802174294Sobrien /* XXX - would it be OK to generate a log record here? */ 2803174294Sobrien err = zfs_freesp(zp, vap->va_size, 0, 0, FALSE); 2804174294Sobrien if (err) { 2805174294Sobrien ZFS_EXIT(zfsvfs); 2806174294Sobrien return (err); 2807174294Sobrien } 2808174294Sobrien } 2809174294Sobrien 2810174294Sobrien if (mask & (AT_ATIME|AT_MTIME) || 2811174294Sobrien ((mask & AT_XVATTR) && (XVA_ISSET_REQ(xvap, XAT_HIDDEN) || 2812174294Sobrien XVA_ISSET_REQ(xvap, XAT_READONLY) || 2813174294Sobrien XVA_ISSET_REQ(xvap, XAT_ARCHIVE) || 2814174294Sobrien XVA_ISSET_REQ(xvap, XAT_CREATETIME) || 2815174294Sobrien XVA_ISSET_REQ(xvap, XAT_SYSTEM)))) 2816174294Sobrien need_policy = zfs_zaccess(zp, ACE_WRITE_ATTRIBUTES, 0, 2817174294Sobrien skipaclchk, cr); 2818174294Sobrien 2819174294Sobrien if (mask & (AT_UID|AT_GID)) { 2820174294Sobrien int idmask = (mask & (AT_UID|AT_GID)); 2821174294Sobrien int take_owner; 2822174294Sobrien int take_group; 2823174294Sobrien 2824174294Sobrien /* 2825174294Sobrien * NOTE: even if a new mode is being set, 2826174294Sobrien * we may clear S_ISUID/S_ISGID bits. 2827174294Sobrien */ 2828174294Sobrien 2829174294Sobrien if (!(mask & AT_MODE)) 2830174294Sobrien vap->va_mode = pzp->zp_mode; 2831174294Sobrien 2832174294Sobrien /* 2833174294Sobrien * Take ownership or chgrp to group we are a member of 2834174294Sobrien */ 2835174294Sobrien 2836174294Sobrien take_owner = (mask & AT_UID) && (vap->va_uid == crgetuid(cr)); 2837174294Sobrien take_group = (mask & AT_GID) && 2838174294Sobrien zfs_groupmember(zfsvfs, vap->va_gid, cr); 2839174294Sobrien 2840174294Sobrien /* 2841174294Sobrien * If both AT_UID and AT_GID are set then take_owner and 2842174294Sobrien * take_group must both be set in order to allow taking 2843174294Sobrien * ownership. 2844174294Sobrien * 2845174294Sobrien * Otherwise, send the check through secpolicy_vnode_setattr() 2846174294Sobrien * 2847174294Sobrien */ 2848174294Sobrien 2849174294Sobrien if (((idmask == (AT_UID|AT_GID)) && take_owner && take_group) || 2850174294Sobrien ((idmask == AT_UID) && take_owner) || 2851174294Sobrien ((idmask == AT_GID) && take_group)) { 2852174294Sobrien if (zfs_zaccess(zp, ACE_WRITE_OWNER, 0, 2853174294Sobrien skipaclchk, cr) == 0) { 2854174294Sobrien /* 2855174294Sobrien * Remove setuid/setgid for non-privileged users 2856174294Sobrien */ 2857174294Sobrien secpolicy_setid_clear(vap, vp, cr); 2858174294Sobrien trim_mask = (mask & (AT_UID|AT_GID)); 2859174294Sobrien } else { 2860174294Sobrien need_policy = TRUE; 2861174294Sobrien } 2862174294Sobrien } else { 2863174294Sobrien need_policy = TRUE; 2864174294Sobrien } 2865174294Sobrien } 2866174294Sobrien 2867174294Sobrien mutex_enter(&zp->z_lock); 2868174294Sobrien oldva.va_mode = pzp->zp_mode; 2869174294Sobrien zfs_fuid_map_ids(zp, cr, &oldva.va_uid, &oldva.va_gid); 2870174294Sobrien if (mask & AT_XVATTR) { 2871174294Sobrien /* 2872174294Sobrien * Update xvattr mask to include only those attributes 2873174294Sobrien * that are actually changing. 2874174294Sobrien * 2875174294Sobrien * the bits will be restored prior to actually setting 2876174294Sobrien * the attributes so the caller thinks they were set. 2877174294Sobrien */ 2878174294Sobrien if (XVA_ISSET_REQ(xvap, XAT_APPENDONLY)) { 2879174294Sobrien if (xoap->xoa_appendonly != 2880174294Sobrien ((pzp->zp_flags & ZFS_APPENDONLY) != 0)) { 2881174294Sobrien need_policy = TRUE; 2882174294Sobrien } else { 2883174294Sobrien XVA_CLR_REQ(xvap, XAT_APPENDONLY); 2884174294Sobrien XVA_SET_REQ(&tmpxvattr, XAT_APPENDONLY); 2885174294Sobrien } 2886174294Sobrien } 2887174294Sobrien 2888174294Sobrien if (XVA_ISSET_REQ(xvap, XAT_NOUNLINK)) { 2889174294Sobrien if (xoap->xoa_nounlink != 2890174294Sobrien ((pzp->zp_flags & ZFS_NOUNLINK) != 0)) { 2891174294Sobrien need_policy = TRUE; 2892174294Sobrien } else { 2893174294Sobrien XVA_CLR_REQ(xvap, XAT_NOUNLINK); 2894174294Sobrien XVA_SET_REQ(&tmpxvattr, XAT_NOUNLINK); 2895174294Sobrien } 2896174294Sobrien } 2897174294Sobrien 2898174294Sobrien if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE)) { 2899174294Sobrien if (xoap->xoa_immutable != 2900174294Sobrien ((pzp->zp_flags & ZFS_IMMUTABLE) != 0)) { 2901174294Sobrien need_policy = TRUE; 2902174294Sobrien } else { 2903174294Sobrien XVA_CLR_REQ(xvap, XAT_IMMUTABLE); 2904174294Sobrien XVA_SET_REQ(&tmpxvattr, XAT_IMMUTABLE); 2905174294Sobrien } 2906174294Sobrien } 2907174294Sobrien 2908174294Sobrien if (XVA_ISSET_REQ(xvap, XAT_NODUMP)) { 2909174294Sobrien if (xoap->xoa_nodump != 2910174294Sobrien ((pzp->zp_flags & ZFS_NODUMP) != 0)) { 2911174294Sobrien need_policy = TRUE; 2912174294Sobrien } else { 2913174294Sobrien XVA_CLR_REQ(xvap, XAT_NODUMP); 2914174294Sobrien XVA_SET_REQ(&tmpxvattr, XAT_NODUMP); 2915174294Sobrien } 2916174294Sobrien } 2917174294Sobrien 2918174294Sobrien if (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED)) { 2919174294Sobrien if (xoap->xoa_av_modified != 2920174294Sobrien ((pzp->zp_flags & ZFS_AV_MODIFIED) != 0)) { 2921174294Sobrien need_policy = TRUE; 2922174294Sobrien } else { 2923174294Sobrien XVA_CLR_REQ(xvap, XAT_AV_MODIFIED); 2924174294Sobrien XVA_SET_REQ(&tmpxvattr, XAT_AV_MODIFIED); 2925174294Sobrien } 2926174294Sobrien } 2927174294Sobrien 2928174294Sobrien if (XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED)) { 2929174294Sobrien if ((vp->v_type != VREG && 2930174294Sobrien xoap->xoa_av_quarantined) || 2931174294Sobrien xoap->xoa_av_quarantined != 2932174294Sobrien ((pzp->zp_flags & ZFS_AV_QUARANTINED) != 0)) { 2933174294Sobrien need_policy = TRUE; 2934174294Sobrien } else { 2935174294Sobrien XVA_CLR_REQ(xvap, XAT_AV_QUARANTINED); 2936174294Sobrien XVA_SET_REQ(&tmpxvattr, XAT_AV_QUARANTINED); 2937174294Sobrien } 2938174294Sobrien } 2939174294Sobrien 2940174294Sobrien if (need_policy == FALSE && 2941174294Sobrien (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP) || 2942174294Sobrien XVA_ISSET_REQ(xvap, XAT_OPAQUE))) { 2943174294Sobrien need_policy = TRUE; 2944174294Sobrien } 2945174294Sobrien } 2946174294Sobrien 2947174294Sobrien mutex_exit(&zp->z_lock); 2948174294Sobrien 2949174294Sobrien if (mask & AT_MODE) { 2950174294Sobrien if (zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr) == 0) { 2951174294Sobrien err = secpolicy_setid_setsticky_clear(vp, vap, 2952174294Sobrien &oldva, cr); 2953174294Sobrien if (err) { 2954174294Sobrien ZFS_EXIT(zfsvfs); 2955174294Sobrien return (err); 2956174294Sobrien } 2957174294Sobrien trim_mask |= AT_MODE; 2958174294Sobrien } else { 2959174294Sobrien need_policy = TRUE; 2960174294Sobrien } 2961174294Sobrien } 2962174294Sobrien 2963174294Sobrien if (need_policy) { 2964174294Sobrien /* 2965174294Sobrien * If trim_mask is set then take ownership 2966174294Sobrien * has been granted or write_acl is present and user 2967174294Sobrien * has the ability to modify mode. In that case remove 2968174294Sobrien * UID|GID and or MODE from mask so that 2969174294Sobrien * secpolicy_vnode_setattr() doesn't revoke it. 2970174294Sobrien */ 2971174294Sobrien 2972174294Sobrien if (trim_mask) { 2973174294Sobrien saved_mask = vap->va_mask; 2974174294Sobrien vap->va_mask &= ~trim_mask; 2975174294Sobrien if (trim_mask & AT_MODE) { 2976174294Sobrien /* 2977174294Sobrien * Save the mode, as secpolicy_vnode_setattr() 2978174294Sobrien * will overwrite it with ova.va_mode. 2979174294Sobrien */ 2980174294Sobrien saved_mode = vap->va_mode; 2981174294Sobrien } 2982174294Sobrien } 2983174294Sobrien err = secpolicy_vnode_setattr(cr, vp, vap, &oldva, flags, 2984174294Sobrien (int (*)(void *, int, cred_t *))zfs_zaccess_unix, zp); 2985174294Sobrien if (err) { 2986174294Sobrien ZFS_EXIT(zfsvfs); 2987174294Sobrien return (err); 2988174294Sobrien } 2989174294Sobrien 2990174294Sobrien if (trim_mask) { 2991174294Sobrien vap->va_mask |= saved_mask; 2992174294Sobrien if (trim_mask & AT_MODE) { 2993174294Sobrien /* 2994174294Sobrien * Recover the mode after 2995174294Sobrien * secpolicy_vnode_setattr(). 2996174294Sobrien */ 2997174294Sobrien vap->va_mode = saved_mode; 2998174294Sobrien } 2999174294Sobrien } 3000174294Sobrien } 3001174294Sobrien 3002174294Sobrien /* 3003174294Sobrien * secpolicy_vnode_setattr, or take ownership may have 3004174294Sobrien * changed va_mask 3005174294Sobrien */ 3006174294Sobrien mask = vap->va_mask; 3007174294Sobrien 3008174294Sobrien tx = dmu_tx_create(zfsvfs->z_os); 3009174294Sobrien dmu_tx_hold_bonus(tx, zp->z_id); 3010174294Sobrien 3011174294Sobrien if (mask & AT_MODE) { 3012174294Sobrien uint64_t pmode = pzp->zp_mode; 3013174294Sobrien 3014174294Sobrien new_mode = (pmode & S_IFMT) | (vap->va_mode & ~S_IFMT); 3015174294Sobrien 3016174294Sobrien if (err = zfs_acl_chmod_setattr(zp, &aclp, new_mode)) 3017174294Sobrien goto out; 3018174294Sobrien if (pzp->zp_acl.z_acl_extern_obj) { 3019174294Sobrien /* Are we upgrading ACL from old V0 format to new V1 */ 3020174294Sobrien if (zfsvfs->z_version <= ZPL_VERSION_FUID && 3021174294Sobrien pzp->zp_acl.z_acl_version == 3022174294Sobrien ZFS_ACL_VERSION_INITIAL) { 3023174294Sobrien dmu_tx_hold_free(tx, 3024174294Sobrien pzp->zp_acl.z_acl_extern_obj, 0, 3025174294Sobrien DMU_OBJECT_END); 3026174294Sobrien dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 3027174294Sobrien 0, aclp->z_acl_bytes); 3028174294Sobrien } else { 3029174294Sobrien dmu_tx_hold_write(tx, 3030174294Sobrien pzp->zp_acl.z_acl_extern_obj, 0, 3031174294Sobrien aclp->z_acl_bytes); 3032174294Sobrien } 3033174294Sobrien } else if (aclp->z_acl_bytes > ZFS_ACE_SPACE) { 3034174294Sobrien dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 3035174294Sobrien 0, aclp->z_acl_bytes); 3036174294Sobrien } 3037174294Sobrien } 3038174294Sobrien 3039174294Sobrien if (mask & (AT_UID | AT_GID)) { 3040174294Sobrien if (pzp->zp_xattr) { 3041174294Sobrien err = zfs_zget(zp->z_zfsvfs, pzp->zp_xattr, &attrzp); 3042174294Sobrien if (err) 3043174294Sobrien goto out; 3044174294Sobrien dmu_tx_hold_bonus(tx, attrzp->z_id); 3045174294Sobrien } 3046174294Sobrien if (mask & AT_UID) { 3047174294Sobrien new_uid = zfs_fuid_create(zfsvfs, 3048174294Sobrien (uint64_t)vap->va_uid, cr, ZFS_OWNER, &fuidp); 3049174294Sobrien if (new_uid != pzp->zp_uid && 3050174294Sobrien zfs_usergroup_overquota(zfsvfs, B_FALSE, new_uid)) { 3051174294Sobrien err = EDQUOT; 3052174294Sobrien goto out; 3053174294Sobrien } 3054174294Sobrien } 3055174294Sobrien 3056174294Sobrien if (mask & AT_GID) { 3057174294Sobrien new_gid = zfs_fuid_create(zfsvfs, (uint64_t)vap->va_gid, 3058174294Sobrien cr, ZFS_GROUP, &fuidp); 3059174294Sobrien if (new_gid != pzp->zp_gid && 3060174294Sobrien zfs_usergroup_overquota(zfsvfs, B_TRUE, new_gid)) { 3061174294Sobrien err = EDQUOT; 3062174294Sobrien goto out; 3063174294Sobrien } 3064174294Sobrien } 3065174294Sobrien fuid_dirtied = zfsvfs->z_fuid_dirty; 3066174294Sobrien if (fuid_dirtied) { 3067174294Sobrien if (zfsvfs->z_fuid_obj == 0) { 3068174294Sobrien dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT); 3069174294Sobrien dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, 3070174294Sobrien FUID_SIZE_ESTIMATE(zfsvfs)); 3071174294Sobrien dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, 3072174294Sobrien FALSE, NULL); 3073174294Sobrien } else { 3074174294Sobrien dmu_tx_hold_bonus(tx, zfsvfs->z_fuid_obj); 3075174294Sobrien dmu_tx_hold_write(tx, zfsvfs->z_fuid_obj, 0, 3076174294Sobrien FUID_SIZE_ESTIMATE(zfsvfs)); 3077174294Sobrien } 3078174294Sobrien } 3079174294Sobrien } 3080174294Sobrien 3081174294Sobrien err = dmu_tx_assign(tx, TXG_NOWAIT); 3082174294Sobrien if (err) { 3083174294Sobrien if (err == ERESTART) 3084174294Sobrien dmu_tx_wait(tx); 3085174294Sobrien goto out; 3086174294Sobrien } 3087174294Sobrien 3088174294Sobrien dmu_buf_will_dirty(zp->z_dbuf, tx); 3089174294Sobrien 3090174294Sobrien /* 3091174294Sobrien * Set each attribute requested. 3092174294Sobrien * We group settings according to the locks they need to acquire. 3093174294Sobrien * 3094174294Sobrien * Note: you cannot set ctime directly, although it will be 3095174294Sobrien * updated as a side-effect of calling this function. 3096174294Sobrien */ 3097174294Sobrien 3098174294Sobrien mutex_enter(&zp->z_lock); 3099174294Sobrien 3100174294Sobrien if (mask & AT_MODE) { 3101174294Sobrien mutex_enter(&zp->z_acl_lock); 3102174294Sobrien zp->z_phys->zp_mode = new_mode; 3103174294Sobrien err = zfs_aclset_common(zp, aclp, cr, tx); 3104174294Sobrien ASSERT3U(err, ==, 0); 3105174294Sobrien zp->z_acl_cached = aclp; 3106174294Sobrien aclp = NULL; 3107174294Sobrien mutex_exit(&zp->z_acl_lock); 3108174294Sobrien } 3109174294Sobrien 3110174294Sobrien if (attrzp) 3111174294Sobrien mutex_enter(&attrzp->z_lock); 3112174294Sobrien 3113174294Sobrien if (mask & AT_UID) { 3114174294Sobrien pzp->zp_uid = new_uid; 3115174294Sobrien if (attrzp) 3116174294Sobrien attrzp->z_phys->zp_uid = new_uid; 3117174294Sobrien } 3118174294Sobrien 3119174294Sobrien if (mask & AT_GID) { 3120174294Sobrien pzp->zp_gid = new_gid; 3121174294Sobrien if (attrzp) 3122174294Sobrien attrzp->z_phys->zp_gid = new_gid; 3123174294Sobrien } 3124174294Sobrien 3125174294Sobrien if (attrzp) 3126174294Sobrien mutex_exit(&attrzp->z_lock); 3127174294Sobrien 3128174294Sobrien if (mask & AT_ATIME) 3129174294Sobrien ZFS_TIME_ENCODE(&vap->va_atime, pzp->zp_atime); 3130174294Sobrien 3131174294Sobrien if (mask & AT_MTIME) 3132174294Sobrien ZFS_TIME_ENCODE(&vap->va_mtime, pzp->zp_mtime); 3133174294Sobrien 3134174294Sobrien /* XXX - shouldn't this be done *before* the ATIME/MTIME checks? */ 3135174294Sobrien if (mask & AT_SIZE) 3136174294Sobrien zfs_time_stamper_locked(zp, CONTENT_MODIFIED, tx); 3137174294Sobrien else if (mask != 0) 3138174294Sobrien zfs_time_stamper_locked(zp, STATE_CHANGED, tx); 3139174294Sobrien /* 3140174294Sobrien * Do this after setting timestamps to prevent timestamp 3141174294Sobrien * update from toggling bit 3142174294Sobrien */ 3143174294Sobrien 3144174294Sobrien if (xoap && (mask & AT_XVATTR)) { 3145174294Sobrien 3146174294Sobrien /* 3147174294Sobrien * restore trimmed off masks 3148174294Sobrien * so that return masks can be set for caller. 3149174294Sobrien */ 3150174294Sobrien 3151174294Sobrien if (XVA_ISSET_REQ(&tmpxvattr, XAT_APPENDONLY)) { 3152174294Sobrien XVA_SET_REQ(xvap, XAT_APPENDONLY); 3153174294Sobrien } 3154174294Sobrien if (XVA_ISSET_REQ(&tmpxvattr, XAT_NOUNLINK)) { 3155174294Sobrien XVA_SET_REQ(xvap, XAT_NOUNLINK); 3156174294Sobrien } 3157174294Sobrien if (XVA_ISSET_REQ(&tmpxvattr, XAT_IMMUTABLE)) { 3158174294Sobrien XVA_SET_REQ(xvap, XAT_IMMUTABLE); 3159174294Sobrien } 3160174294Sobrien if (XVA_ISSET_REQ(&tmpxvattr, XAT_NODUMP)) { 3161174294Sobrien XVA_SET_REQ(xvap, XAT_NODUMP); 3162174294Sobrien } 3163174294Sobrien if (XVA_ISSET_REQ(&tmpxvattr, XAT_AV_MODIFIED)) { 3164174294Sobrien XVA_SET_REQ(xvap, XAT_AV_MODIFIED); 3165174294Sobrien } 3166174294Sobrien if (XVA_ISSET_REQ(&tmpxvattr, XAT_AV_QUARANTINED)) { 3167174294Sobrien XVA_SET_REQ(xvap, XAT_AV_QUARANTINED); 3168174294Sobrien } 3169174294Sobrien 3170174294Sobrien if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) { 3171174294Sobrien size_t len; 3172174294Sobrien dmu_object_info_t doi; 3173174294Sobrien 3174174294Sobrien ASSERT(vp->v_type == VREG); 3175174294Sobrien 3176174294Sobrien /* Grow the bonus buffer if necessary. */ 3177174294Sobrien dmu_object_info_from_db(zp->z_dbuf, &doi); 3178174294Sobrien len = sizeof (xoap->xoa_av_scanstamp) + 3179174294Sobrien sizeof (znode_phys_t); 3180174294Sobrien if (len > doi.doi_bonus_size) 3181174294Sobrien VERIFY(dmu_set_bonus(zp->z_dbuf, len, tx) == 0); 3182174294Sobrien } 3183174294Sobrien zfs_xvattr_set(zp, xvap); 3184174294Sobrien } 3185119679Smbr 3186119679Smbr if (fuid_dirtied) 3187174294Sobrien zfs_fuid_sync(zfsvfs, tx); 3188174294Sobrien 3189119679Smbr if (mask != 0) 3190174294Sobrien zfs_log_setattr(zilog, tx, TX_SETATTR, zp, vap, mask, fuidp); 3191174294Sobrien 3192174294Sobrien mutex_exit(&zp->z_lock); 3193174294Sobrien 3194174294Sobrienout: 3195174294Sobrien if (attrzp) 3196174294Sobrien VN_RELE(ZTOV(attrzp)); 3197174294Sobrien 3198174294Sobrien if (aclp) 3199174294Sobrien zfs_acl_free(aclp); 3200174294Sobrien 3201174294Sobrien if (fuidp) { 3202174294Sobrien zfs_fuid_info_free(fuidp); 3203174294Sobrien fuidp = NULL; 3204174294Sobrien } 3205174294Sobrien 3206174294Sobrien if (err) 3207174294Sobrien dmu_tx_abort(tx); 3208174294Sobrien else 3209174294Sobrien dmu_tx_commit(tx); 3210174294Sobrien 3211174294Sobrien if (err == ERESTART) 3212174294Sobrien goto top; 3213174294Sobrien 3214174294Sobrien ZFS_EXIT(zfsvfs); 3215174294Sobrien return (err); 3216174294Sobrien} 3217174294Sobrien 3218174294Sobrientypedef struct zfs_zlock { 3219174294Sobrien krwlock_t *zl_rwlock; /* lock we acquired */ 3220174294Sobrien znode_t *zl_znode; /* znode we held */ 3221174294Sobrien struct zfs_zlock *zl_next; /* next in list */ 3222174294Sobrien} zfs_zlock_t; 3223174294Sobrien 3224174294Sobrien/* 3225174294Sobrien * Drop locks and release vnodes that were held by zfs_rename_lock(). 3226174294Sobrien */ 3227174294Sobrienstatic void 3228174294Sobrienzfs_rename_unlock(zfs_zlock_t **zlpp) 3229174294Sobrien{ 3230174294Sobrien zfs_zlock_t *zl; 3231174294Sobrien 3232174294Sobrien while ((zl = *zlpp) != NULL) { 3233174294Sobrien if (zl->zl_znode != NULL) 3234174294Sobrien VN_RELE(ZTOV(zl->zl_znode)); 3235174294Sobrien rw_exit(zl->zl_rwlock); 3236174294Sobrien *zlpp = zl->zl_next; 3237174294Sobrien kmem_free(zl, sizeof (*zl)); 3238174294Sobrien } 3239174294Sobrien} 3240174294Sobrien 3241174294Sobrien/* 3242174294Sobrien * Search back through the directory tree, using the ".." entries. 3243174294Sobrien * Lock each directory in the chain to prevent concurrent renames. 3244174294Sobrien * Fail any attempt to move a directory into one of its own descendants. 3245174294Sobrien * XXX - z_parent_lock can overlap with map or grow locks 3246174294Sobrien */ 3247174294Sobrienstatic int 3248174294Sobrienzfs_rename_lock(znode_t *szp, znode_t *tdzp, znode_t *sdzp, zfs_zlock_t **zlpp) 3249174294Sobrien{ 3250174294Sobrien zfs_zlock_t *zl; 3251174294Sobrien znode_t *zp = tdzp; 3252174294Sobrien uint64_t rootid = zp->z_zfsvfs->z_root; 3253174294Sobrien uint64_t *oidp = &zp->z_id; 3254174294Sobrien krwlock_t *rwlp = &szp->z_parent_lock; 3255174294Sobrien krw_t rw = RW_WRITER; 3256174294Sobrien 3257174294Sobrien /* 3258174294Sobrien * First pass write-locks szp and compares to zp->z_id. 3259174294Sobrien * Later passes read-lock zp and compare to zp->z_parent. 3260174294Sobrien */ 3261174294Sobrien do { 3262174294Sobrien if (!rw_tryenter(rwlp, rw)) { 3263174294Sobrien /* 3264174294Sobrien * Another thread is renaming in this path. 3265174294Sobrien * Note that if we are a WRITER, we don't have any 3266174294Sobrien * parent_locks held yet. 3267174294Sobrien */ 3268174294Sobrien if (rw == RW_READER && zp->z_id > szp->z_id) { 3269174294Sobrien /* 3270174294Sobrien * Drop our locks and restart 3271174294Sobrien */ 3272174294Sobrien zfs_rename_unlock(&zl); 3273174294Sobrien *zlpp = NULL; 3274174294Sobrien zp = tdzp; 3275174294Sobrien oidp = &zp->z_id; 3276174294Sobrien rwlp = &szp->z_parent_lock; 3277174294Sobrien rw = RW_WRITER; 3278174294Sobrien continue; 3279174294Sobrien } else { 3280174294Sobrien /* 3281174294Sobrien * Wait for other thread to drop its locks 3282174294Sobrien */ 3283174294Sobrien rw_enter(rwlp, rw); 3284174294Sobrien } 3285174294Sobrien } 3286174294Sobrien 3287174294Sobrien zl = kmem_alloc(sizeof (*zl), KM_SLEEP); 3288174294Sobrien zl->zl_rwlock = rwlp; 3289174294Sobrien zl->zl_znode = NULL; 3290174294Sobrien zl->zl_next = *zlpp; 3291174294Sobrien *zlpp = zl; 3292174294Sobrien 3293174294Sobrien if (*oidp == szp->z_id) /* We're a descendant of szp */ 3294174294Sobrien return (EINVAL); 3295174294Sobrien 3296174294Sobrien if (*oidp == rootid) /* We've hit the top */ 3297174294Sobrien return (0); 3298174294Sobrien 3299174294Sobrien if (rw == RW_READER) { /* i.e. not the first pass */ 3300174294Sobrien int error = zfs_zget(zp->z_zfsvfs, *oidp, &zp); 3301119679Smbr if (error) 3302119679Smbr return (error); 3303119679Smbr zl->zl_znode = zp; 3304119679Smbr } 3305119679Smbr oidp = &zp->z_phys->zp_parent; 3306119679Smbr rwlp = &zp->z_parent_lock; 3307174294Sobrien rw = RW_READER; 3308174294Sobrien 3309174294Sobrien } while (zp->z_id != sdzp->z_id); 3310174294Sobrien 3311174294Sobrien return (0); 3312174294Sobrien} 3313174294Sobrien 3314174294Sobrien/* 3315174294Sobrien * Move an entry from the provided source directory to the target 3316174294Sobrien * directory. Change the entry name as indicated. 3317174294Sobrien * 3318174294Sobrien * IN: sdvp - Source directory containing the "old entry". 3319174294Sobrien * snm - Old entry name. 3320174294Sobrien * tdvp - Target directory to contain the "new entry". 3321174294Sobrien * tnm - New entry name. 3322174294Sobrien * cr - credentials of caller. 3323174294Sobrien * ct - caller context 3324174294Sobrien * flags - case flags 3325174294Sobrien * 3326174294Sobrien * RETURN: 0 if success 3327174294Sobrien * error code if failure 3328174294Sobrien * 3329174294Sobrien * Timestamps: 3330174294Sobrien * sdvp,tdvp - ctime|mtime updated 3331174294Sobrien */ 3332174294Sobrien/*ARGSUSED*/ 3333174294Sobrienstatic int 3334174294Sobrienzfs_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr, 3335174294Sobrien caller_context_t *ct, int flags) 3336174294Sobrien{ 3337174294Sobrien znode_t *tdzp, *szp, *tzp; 3338174294Sobrien znode_t *sdzp = VTOZ(sdvp); 3339174294Sobrien zfsvfs_t *zfsvfs = sdzp->z_zfsvfs; 3340174294Sobrien zilog_t *zilog; 3341174294Sobrien vnode_t *realvp; 3342174294Sobrien zfs_dirlock_t *sdl, *tdl; 3343174294Sobrien dmu_tx_t *tx; 3344174294Sobrien zfs_zlock_t *zl; 3345174294Sobrien int cmp, serr, terr; 3346174294Sobrien int error = 0; 3347174294Sobrien int zflg = 0; 3348174294Sobrien 3349174294Sobrien ZFS_ENTER(zfsvfs); 3350174294Sobrien ZFS_VERIFY_ZP(sdzp); 3351174294Sobrien zilog = zfsvfs->z_log; 3352174294Sobrien 3353174294Sobrien /* 3354174294Sobrien * Make sure we have the real vp for the target directory. 3355174294Sobrien */ 3356174294Sobrien if (VOP_REALVP(tdvp, &realvp, ct) == 0) 3357174294Sobrien tdvp = realvp; 3358174294Sobrien 3359174294Sobrien if (tdvp->v_vfsp != sdvp->v_vfsp || zfsctl_is_node(tdvp)) { 3360174294Sobrien ZFS_EXIT(zfsvfs); 3361174294Sobrien return (EXDEV); 3362174294Sobrien } 3363174294Sobrien 3364174294Sobrien tdzp = VTOZ(tdvp); 3365174294Sobrien ZFS_VERIFY_ZP(tdzp); 3366174294Sobrien if (zfsvfs->z_utf8 && u8_validate(tnm, 3367174294Sobrien strlen(tnm), NULL, U8_VALIDATE_ENTIRE, &error) < 0) { 3368174294Sobrien ZFS_EXIT(zfsvfs); 3369174294Sobrien return (EILSEQ); 3370174294Sobrien } 3371174294Sobrien 3372174294Sobrien if (flags & FIGNORECASE) 3373174294Sobrien zflg |= ZCILOOK; 3374174294Sobrien 3375174294Sobrientop: 3376174294Sobrien szp = NULL; 3377174294Sobrien tzp = NULL; 3378174294Sobrien zl = NULL; 3379174294Sobrien 3380174294Sobrien /* 3381174294Sobrien * This is to prevent the creation of links into attribute space 3382174294Sobrien * by renaming a linked file into/outof an attribute directory. 3383174294Sobrien * See the comment in zfs_link() for why this is considered bad. 3384174294Sobrien */ 3385174294Sobrien if ((tdzp->z_phys->zp_flags & ZFS_XATTR) != 3386174294Sobrien (sdzp->z_phys->zp_flags & ZFS_XATTR)) { 3387174294Sobrien ZFS_EXIT(zfsvfs); 3388174294Sobrien return (EINVAL); 3389174294Sobrien } 3390174294Sobrien 3391174294Sobrien /* 3392174294Sobrien * Lock source and target directory entries. To prevent deadlock, 3393174294Sobrien * a lock ordering must be defined. We lock the directory with 3394174294Sobrien * the smallest object id first, or if it's a tie, the one with 3395174294Sobrien * the lexically first name. 3396174294Sobrien */ 3397174294Sobrien if (sdzp->z_id < tdzp->z_id) { 3398174294Sobrien cmp = -1; 3399174294Sobrien } else if (sdzp->z_id > tdzp->z_id) { 3400174294Sobrien cmp = 1; 3401174294Sobrien } else { 3402174294Sobrien /* 3403174294Sobrien * First compare the two name arguments without 3404174294Sobrien * considering any case folding. 3405174294Sobrien */ 3406174294Sobrien int nofold = (zfsvfs->z_norm & ~U8_TEXTPREP_TOUPPER); 3407174294Sobrien 3408174294Sobrien cmp = u8_strcmp(snm, tnm, 0, nofold, U8_UNICODE_LATEST, &error); 3409174294Sobrien ASSERT(error == 0 || !zfsvfs->z_utf8); 3410174294Sobrien if (cmp == 0) { 3411174294Sobrien /* 3412174294Sobrien * POSIX: "If the old argument and the new argument 3413174294Sobrien * both refer to links to the same existing file, 3414174294Sobrien * the rename() function shall return successfully 3415174294Sobrien * and perform no other action." 3416174294Sobrien */ 3417174294Sobrien ZFS_EXIT(zfsvfs); 3418174294Sobrien return (0); 3419174294Sobrien } 3420174294Sobrien /* 3421174294Sobrien * If the file system is case-folding, then we may 3422174294Sobrien * have some more checking to do. A case-folding file 3423174294Sobrien * system is either supporting mixed case sensitivity 3424174294Sobrien * access or is completely case-insensitive. Note 3425174294Sobrien * that the file system is always case preserving. 3426174294Sobrien * 3427174294Sobrien * In mixed sensitivity mode case sensitive behavior 3428174294Sobrien * is the default. FIGNORECASE must be used to 3429174294Sobrien * explicitly request case insensitive behavior. 3430174294Sobrien * 3431174294Sobrien * If the source and target names provided differ only 3432174294Sobrien * by case (e.g., a request to rename 'tim' to 'Tim'), 3433174294Sobrien * we will treat this as a special case in the 3434174294Sobrien * case-insensitive mode: as long as the source name 3435174294Sobrien * is an exact match, we will allow this to proceed as 3436174294Sobrien * a name-change request. 3437174294Sobrien */ 3438174294Sobrien if ((zfsvfs->z_case == ZFS_CASE_INSENSITIVE || 3439174294Sobrien (zfsvfs->z_case == ZFS_CASE_MIXED && 3440174294Sobrien flags & FIGNORECASE)) && 3441174294Sobrien u8_strcmp(snm, tnm, 0, zfsvfs->z_norm, U8_UNICODE_LATEST, 3442174294Sobrien &error) == 0) { 3443174294Sobrien /* 3444174294Sobrien * case preserving rename request, require exact 3445174294Sobrien * name matches 3446174294Sobrien */ 3447174294Sobrien zflg |= ZCIEXACT; 3448174294Sobrien zflg &= ~ZCILOOK; 3449174294Sobrien } 3450174294Sobrien } 3451174294Sobrien 3452174294Sobrien /* 3453174294Sobrien * If the source and destination directories are the same, we should 3454174294Sobrien * grab the z_name_lock of that directory only once. 3455174294Sobrien */ 3456174294Sobrien if (sdzp == tdzp) { 3457174294Sobrien zflg |= ZHAVELOCK; 3458174294Sobrien rw_enter(&sdzp->z_name_lock, RW_READER); 3459174294Sobrien } 3460174294Sobrien 3461174294Sobrien if (cmp < 0) { 3462174294Sobrien serr = zfs_dirent_lock(&sdl, sdzp, snm, &szp, 3463174294Sobrien ZEXISTS | zflg, NULL, NULL); 3464174294Sobrien terr = zfs_dirent_lock(&tdl, 3465174294Sobrien tdzp, tnm, &tzp, ZRENAMING | zflg, NULL, NULL); 3466174294Sobrien } else { 3467174294Sobrien terr = zfs_dirent_lock(&tdl, 3468174294Sobrien tdzp, tnm, &tzp, zflg, NULL, NULL); 3469174294Sobrien serr = zfs_dirent_lock(&sdl, 3470174294Sobrien sdzp, snm, &szp, ZEXISTS | ZRENAMING | zflg, 3471174294Sobrien NULL, NULL); 3472174294Sobrien } 3473174294Sobrien 3474174294Sobrien if (serr) { 3475174294Sobrien /* 3476174294Sobrien * Source entry invalid or not there. 3477174294Sobrien */ 3478174294Sobrien if (!terr) { 3479174294Sobrien zfs_dirent_unlock(tdl); 3480174294Sobrien if (tzp) 3481174294Sobrien VN_RELE(ZTOV(tzp)); 3482174294Sobrien } 3483174294Sobrien 3484174294Sobrien if (sdzp == tdzp) 3485174294Sobrien rw_exit(&sdzp->z_name_lock); 3486174294Sobrien 3487174294Sobrien if (strcmp(snm, ".") == 0 || strcmp(snm, "..") == 0) 3488174294Sobrien serr = EINVAL; 3489174294Sobrien ZFS_EXIT(zfsvfs); 3490174294Sobrien return (serr); 3491174294Sobrien } 3492174294Sobrien if (terr) { 3493174294Sobrien zfs_dirent_unlock(sdl); 3494174294Sobrien VN_RELE(ZTOV(szp)); 3495174294Sobrien 3496174294Sobrien if (sdzp == tdzp) 3497174294Sobrien rw_exit(&sdzp->z_name_lock); 3498174294Sobrien 3499174294Sobrien if (strcmp(tnm, "..") == 0) 3500174294Sobrien terr = EINVAL; 3501174294Sobrien ZFS_EXIT(zfsvfs); 3502174294Sobrien return (terr); 3503174294Sobrien } 3504174294Sobrien 3505174294Sobrien /* 3506174294Sobrien * Must have write access at the source to remove the old entry 3507174294Sobrien * and write access at the target to create the new entry. 3508174294Sobrien * Note that if target and source are the same, this can be 3509174294Sobrien * done in a single check. 3510174294Sobrien */ 3511174294Sobrien 3512174294Sobrien if (error = zfs_zaccess_rename(sdzp, szp, tdzp, tzp, cr)) 3513174294Sobrien goto out; 3514174294Sobrien 3515174294Sobrien if (ZTOV(szp)->v_type == VDIR) { 3516174294Sobrien /* 3517174294Sobrien * Check to make sure rename is valid. 3518174294Sobrien * Can't do a move like this: /usr/a/b to /usr/a/b/c/d 3519174294Sobrien */ 3520174294Sobrien if (error = zfs_rename_lock(szp, tdzp, sdzp, &zl)) 3521174294Sobrien goto out; 3522174294Sobrien } 3523174294Sobrien 3524174294Sobrien /* 3525174294Sobrien * Does target exist? 3526174294Sobrien */ 3527174294Sobrien if (tzp) { 3528174294Sobrien /* 3529174294Sobrien * Source and target must be the same type. 3530174294Sobrien */ 3531174294Sobrien if (ZTOV(szp)->v_type == VDIR) { 3532174294Sobrien if (ZTOV(tzp)->v_type != VDIR) { 3533174294Sobrien error = ENOTDIR; 3534174294Sobrien goto out; 3535174294Sobrien } 3536174294Sobrien } else { 3537174294Sobrien if (ZTOV(tzp)->v_type == VDIR) { 3538174294Sobrien error = EISDIR; 3539174294Sobrien goto out; 3540174294Sobrien } 3541174294Sobrien } 3542174294Sobrien /* 3543174294Sobrien * POSIX dictates that when the source and target 3544174294Sobrien * entries refer to the same file object, rename 3545174294Sobrien * must do nothing and exit without error. 3546174294Sobrien */ 3547174294Sobrien if (szp->z_id == tzp->z_id) { 3548174294Sobrien error = 0; 3549174294Sobrien goto out; 3550174294Sobrien } 3551174294Sobrien } 3552174294Sobrien 3553174294Sobrien vnevent_rename_src(ZTOV(szp), sdvp, snm, ct); 3554174294Sobrien if (tzp) 3555174294Sobrien vnevent_rename_dest(ZTOV(tzp), tdvp, tnm, ct); 3556174294Sobrien 3557174294Sobrien /* 3558174294Sobrien * notify the target directory if it is not the same 3559174294Sobrien * as source directory. 3560174294Sobrien */ 3561174294Sobrien if (tdvp != sdvp) { 3562174294Sobrien vnevent_rename_dest_dir(tdvp, ct); 3563174294Sobrien } 3564174294Sobrien 3565174294Sobrien tx = dmu_tx_create(zfsvfs->z_os); 3566174294Sobrien dmu_tx_hold_bonus(tx, szp->z_id); /* nlink changes */ 3567174294Sobrien dmu_tx_hold_bonus(tx, sdzp->z_id); /* nlink changes */ 3568174294Sobrien dmu_tx_hold_zap(tx, sdzp->z_id, FALSE, snm); 3569174294Sobrien dmu_tx_hold_zap(tx, tdzp->z_id, TRUE, tnm); 3570174294Sobrien if (sdzp != tdzp) 3571174294Sobrien dmu_tx_hold_bonus(tx, tdzp->z_id); /* nlink changes */ 3572174294Sobrien if (tzp) 3573174294Sobrien dmu_tx_hold_bonus(tx, tzp->z_id); /* parent changes */ 3574174294Sobrien dmu_tx_hold_zap(tx, zfsvfs->z_unlinkedobj, FALSE, NULL); 3575174294Sobrien error = dmu_tx_assign(tx, TXG_NOWAIT); 3576174294Sobrien if (error) { 3577174294Sobrien if (zl != NULL) 3578174294Sobrien zfs_rename_unlock(&zl); 3579174294Sobrien zfs_dirent_unlock(sdl); 3580174294Sobrien zfs_dirent_unlock(tdl); 3581174294Sobrien 3582174294Sobrien if (sdzp == tdzp) 3583174294Sobrien rw_exit(&sdzp->z_name_lock); 3584174294Sobrien 3585174294Sobrien VN_RELE(ZTOV(szp)); 3586174294Sobrien if (tzp) 3587174294Sobrien VN_RELE(ZTOV(tzp)); 3588174294Sobrien if (error == ERESTART) { 3589174294Sobrien dmu_tx_wait(tx); 3590174294Sobrien dmu_tx_abort(tx); 3591174294Sobrien goto top; 3592174294Sobrien } 3593174294Sobrien dmu_tx_abort(tx); 3594174294Sobrien ZFS_EXIT(zfsvfs); 3595174294Sobrien return (error); 3596174294Sobrien } 3597174294Sobrien 3598174294Sobrien if (tzp) /* Attempt to remove the existing target */ 3599174294Sobrien error = zfs_link_destroy(tdl, tzp, tx, zflg, NULL); 3600174294Sobrien 3601174294Sobrien if (error == 0) { 3602174294Sobrien error = zfs_link_create(tdl, szp, tx, ZRENAMING); 3603174294Sobrien if (error == 0) { 3604174294Sobrien szp->z_phys->zp_flags |= ZFS_AV_MODIFIED; 3605174294Sobrien 3606174294Sobrien error = zfs_link_destroy(sdl, szp, tx, ZRENAMING, NULL); 3607174294Sobrien ASSERT(error == 0); 3608174294Sobrien 3609174294Sobrien zfs_log_rename(zilog, tx, 3610174294Sobrien TX_RENAME | (flags & FIGNORECASE ? TX_CI : 0), 3611174294Sobrien sdzp, sdl->dl_name, tdzp, tdl->dl_name, szp); 3612174294Sobrien 3613174294Sobrien /* Update path information for the target vnode */ 3614174294Sobrien vn_renamepath(tdvp, ZTOV(szp), tnm, strlen(tnm)); 3615174294Sobrien } 3616174294Sobrien#ifdef FREEBSD_NAMECACHE 3617174294Sobrien if (error == 0) { 3618174294Sobrien cache_purge(sdvp); 3619174294Sobrien cache_purge(tdvp); 3620174294Sobrien } 3621174294Sobrien#endif 3622174294Sobrien } 3623174294Sobrien 3624174294Sobrien dmu_tx_commit(tx); 3625174294Sobrienout: 3626174294Sobrien if (zl != NULL) 3627174294Sobrien zfs_rename_unlock(&zl); 3628174294Sobrien 3629174294Sobrien zfs_dirent_unlock(sdl); 3630174294Sobrien zfs_dirent_unlock(tdl); 3631174294Sobrien 3632174294Sobrien if (sdzp == tdzp) 3633174294Sobrien rw_exit(&sdzp->z_name_lock); 3634174294Sobrien 3635174294Sobrien VN_RELE(ZTOV(szp)); 3636174294Sobrien if (tzp) 3637174294Sobrien VN_RELE(ZTOV(tzp)); 3638174294Sobrien 3639174294Sobrien ZFS_EXIT(zfsvfs); 3640174294Sobrien 3641174294Sobrien return (error); 3642174294Sobrien} 3643174294Sobrien 3644174294Sobrien/* 3645174294Sobrien * Insert the indicated symbolic reference entry into the directory. 3646174294Sobrien * 3647174294Sobrien * IN: dvp - Directory to contain new symbolic link. 3648174294Sobrien * link - Name for new symlink entry. 3649174294Sobrien * vap - Attributes of new entry. 3650174294Sobrien * target - Target path of new symlink. 3651174294Sobrien * cr - credentials of caller. 3652174294Sobrien * ct - caller context 3653174294Sobrien * flags - case flags 3654174294Sobrien * 3655174294Sobrien * RETURN: 0 if success 3656174294Sobrien * error code if failure 3657174294Sobrien * 3658174294Sobrien * Timestamps: 3659174294Sobrien * dvp - ctime|mtime updated 3660174294Sobrien */ 3661174294Sobrien/*ARGSUSED*/ 3662174294Sobrienstatic int 3663174294Sobrienzfs_symlink(vnode_t *dvp, vnode_t **vpp, char *name, vattr_t *vap, char *link, 3664174294Sobrien cred_t *cr, kthread_t *td) 3665174294Sobrien{ 3666174294Sobrien znode_t *zp, *dzp = VTOZ(dvp); 3667174294Sobrien zfs_dirlock_t *dl; 3668174294Sobrien dmu_tx_t *tx; 3669174294Sobrien zfsvfs_t *zfsvfs = dzp->z_zfsvfs; 3670174294Sobrien zilog_t *zilog; 3671174294Sobrien int len = strlen(link); 3672174294Sobrien int error; 3673174294Sobrien int zflg = ZNEW; 3674174294Sobrien zfs_acl_ids_t acl_ids; 3675174294Sobrien boolean_t fuid_dirtied; 3676174294Sobrien int flags = 0; 3677174294Sobrien 3678174294Sobrien ASSERT(vap->va_type == VLNK); 3679174294Sobrien 3680174294Sobrien ZFS_ENTER(zfsvfs); 3681174294Sobrien ZFS_VERIFY_ZP(dzp); 3682174294Sobrien zilog = zfsvfs->z_log; 3683174294Sobrien 3684174294Sobrien if (zfsvfs->z_utf8 && u8_validate(name, strlen(name), 3685174294Sobrien NULL, U8_VALIDATE_ENTIRE, &error) < 0) { 3686174294Sobrien ZFS_EXIT(zfsvfs); 3687174294Sobrien return (EILSEQ); 3688174294Sobrien } 3689174294Sobrien if (flags & FIGNORECASE) 3690174294Sobrien zflg |= ZCILOOK; 3691174294Sobrientop: 3692174294Sobrien if (error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr)) { 3693174294Sobrien ZFS_EXIT(zfsvfs); 3694174294Sobrien return (error); 3695174294Sobrien } 3696174294Sobrien 3697174294Sobrien if (len > MAXPATHLEN) { 3698174294Sobrien ZFS_EXIT(zfsvfs); 3699174294Sobrien return (ENAMETOOLONG); 3700174294Sobrien } 3701174294Sobrien 3702174294Sobrien /* 3703174294Sobrien * Attempt to lock directory; fail if entry already exists. 3704174294Sobrien */ 3705174294Sobrien error = zfs_dirent_lock(&dl, dzp, name, &zp, zflg, NULL, NULL); 3706174294Sobrien if (error) { 3707174294Sobrien ZFS_EXIT(zfsvfs); 3708174294Sobrien return (error); 3709174294Sobrien } 3710174294Sobrien 3711174294Sobrien VERIFY(0 == zfs_acl_ids_create(dzp, 0, vap, cr, NULL, &acl_ids)); 3712174294Sobrien if (zfs_acl_ids_overquota(zfsvfs, &acl_ids)) { 3713174294Sobrien zfs_acl_ids_free(&acl_ids); 3714174294Sobrien zfs_dirent_unlock(dl); 3715174294Sobrien ZFS_EXIT(zfsvfs); 3716174294Sobrien return (EDQUOT); 3717174294Sobrien } 3718174294Sobrien tx = dmu_tx_create(zfsvfs->z_os); 3719174294Sobrien fuid_dirtied = zfsvfs->z_fuid_dirty; 3720174294Sobrien dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, MAX(1, len)); 3721174294Sobrien dmu_tx_hold_bonus(tx, dzp->z_id); 3722174294Sobrien dmu_tx_hold_zap(tx, dzp->z_id, TRUE, name); 3723174294Sobrien if (acl_ids.z_aclp->z_acl_bytes > ZFS_ACE_SPACE) 3724174294Sobrien dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, SPA_MAXBLOCKSIZE); 3725174294Sobrien if (fuid_dirtied) 3726174294Sobrien zfs_fuid_txhold(zfsvfs, tx); 3727174294Sobrien error = dmu_tx_assign(tx, TXG_NOWAIT); 3728174294Sobrien if (error) { 3729174294Sobrien zfs_acl_ids_free(&acl_ids); 3730174294Sobrien zfs_dirent_unlock(dl); 3731174294Sobrien if (error == ERESTART) { 3732174294Sobrien dmu_tx_wait(tx); 3733174294Sobrien dmu_tx_abort(tx); 3734174294Sobrien goto top; 3735174294Sobrien } 3736174294Sobrien dmu_tx_abort(tx); 3737174294Sobrien ZFS_EXIT(zfsvfs); 3738174294Sobrien return (error); 3739174294Sobrien } 3740174294Sobrien 3741174294Sobrien dmu_buf_will_dirty(dzp->z_dbuf, tx); 3742174294Sobrien 3743174294Sobrien /* 3744174294Sobrien * Create a new object for the symlink. 3745174294Sobrien * Put the link content into bonus buffer if it will fit; 3746174294Sobrien * otherwise, store it just like any other file data. 3747174294Sobrien */ 3748174294Sobrien if (sizeof (znode_phys_t) + len <= dmu_bonus_max()) { 3749174294Sobrien zfs_mknode(dzp, vap, tx, cr, 0, &zp, len, &acl_ids); 3750174294Sobrien if (len != 0) 3751174294Sobrien bcopy(link, zp->z_phys + 1, len); 3752174294Sobrien } else { 3753174294Sobrien dmu_buf_t *dbp; 3754174294Sobrien 3755174294Sobrien zfs_mknode(dzp, vap, tx, cr, 0, &zp, 0, &acl_ids); 3756174294Sobrien 3757174294Sobrien if (fuid_dirtied) 3758174294Sobrien zfs_fuid_sync(zfsvfs, tx); 3759174294Sobrien /* 3760174294Sobrien * Nothing can access the znode yet so no locking needed 3761174294Sobrien * for growing the znode's blocksize. 3762174294Sobrien */ 3763174294Sobrien zfs_grow_blocksize(zp, len, tx); 3764174294Sobrien 3765174294Sobrien VERIFY(0 == dmu_buf_hold(zfsvfs->z_os, 3766174294Sobrien zp->z_id, 0, FTAG, &dbp)); 3767174294Sobrien dmu_buf_will_dirty(dbp, tx); 3768174294Sobrien 3769174294Sobrien ASSERT3U(len, <=, dbp->db_size); 3770174294Sobrien bcopy(link, dbp->db_data, len); 3771174294Sobrien dmu_buf_rele(dbp, FTAG); 3772174294Sobrien } 3773174294Sobrien zp->z_phys->zp_size = len; 3774174294Sobrien 3775174294Sobrien /* 3776174294Sobrien * Insert the new object into the directory. 3777174294Sobrien */ 3778174294Sobrien (void) zfs_link_create(dl, zp, tx, ZNEW); 3779174294Sobrien if (error == 0) { 3780174294Sobrien uint64_t txtype = TX_SYMLINK; 3781174294Sobrien if (flags & FIGNORECASE) 3782174294Sobrien txtype |= TX_CI; 3783174294Sobrien zfs_log_symlink(zilog, tx, txtype, dzp, zp, name, link); 3784174294Sobrien *vpp = ZTOV(zp); 3785174294Sobrien } 3786174294Sobrien 3787174294Sobrien zfs_acl_ids_free(&acl_ids); 3788174294Sobrien 3789174294Sobrien dmu_tx_commit(tx); 3790174294Sobrien 3791174294Sobrien zfs_dirent_unlock(dl); 3792174294Sobrien 3793174294Sobrien ZFS_EXIT(zfsvfs); 3794174294Sobrien return (error); 3795174294Sobrien} 3796174294Sobrien 3797174294Sobrien/* 3798174294Sobrien * Return, in the buffer contained in the provided uio structure, 3799174294Sobrien * the symbolic path referred to by vp. 3800174294Sobrien * 3801174294Sobrien * IN: vp - vnode of symbolic link. 3802174294Sobrien * uoip - structure to contain the link path. 3803174294Sobrien * cr - credentials of caller. 3804174294Sobrien * ct - caller context 3805174294Sobrien * 3806174294Sobrien * OUT: uio - structure to contain the link path. 3807174294Sobrien * 3808174294Sobrien * RETURN: 0 if success 3809174294Sobrien * error code if failure 3810174294Sobrien * 3811174294Sobrien * Timestamps: 3812174294Sobrien * vp - atime updated 3813174294Sobrien */ 3814174294Sobrien/* ARGSUSED */ 3815174294Sobrienstatic int 3816174294Sobrienzfs_readlink(vnode_t *vp, uio_t *uio, cred_t *cr, caller_context_t *ct) 3817174294Sobrien{ 3818174294Sobrien znode_t *zp = VTOZ(vp); 3819174294Sobrien zfsvfs_t *zfsvfs = zp->z_zfsvfs; 3820174294Sobrien size_t bufsz; 3821174294Sobrien int error; 3822174294Sobrien 3823174294Sobrien ZFS_ENTER(zfsvfs); 3824174294Sobrien ZFS_VERIFY_ZP(zp); 3825174294Sobrien 3826174294Sobrien bufsz = (size_t)zp->z_phys->zp_size; 3827174294Sobrien if (bufsz + sizeof (znode_phys_t) <= zp->z_dbuf->db_size) { 3828174294Sobrien error = uiomove(zp->z_phys + 1, 3829174294Sobrien MIN((size_t)bufsz, uio->uio_resid), UIO_READ, uio); 3830174294Sobrien } else { 3831174294Sobrien dmu_buf_t *dbp; 3832174294Sobrien error = dmu_buf_hold(zfsvfs->z_os, zp->z_id, 0, FTAG, &dbp); 3833174294Sobrien if (error) { 3834174294Sobrien ZFS_EXIT(zfsvfs); 3835174294Sobrien return (error); 3836174294Sobrien } 3837174294Sobrien error = uiomove(dbp->db_data, 3838174294Sobrien MIN((size_t)bufsz, uio->uio_resid), UIO_READ, uio); 3839174294Sobrien dmu_buf_rele(dbp, FTAG); 3840174294Sobrien } 3841119679Smbr 3842119679Smbr ZFS_ACCESSTIME_STAMP(zfsvfs, zp); 3843174294Sobrien ZFS_EXIT(zfsvfs); 3844174294Sobrien return (error); 3845174294Sobrien} 3846174294Sobrien 3847174294Sobrien/* 3848119679Smbr * Insert a new entry into directory tdvp referencing svp. 3849119679Smbr * 3850119679Smbr * IN: tdvp - Directory to contain new entry. 3851174294Sobrien * svp - vnode of new entry. 3852119679Smbr * name - name of new entry. 3853174294Sobrien * cr - credentials of caller. 3854119679Smbr * ct - caller context 3855174294Sobrien * 3856174294Sobrien * RETURN: 0 if success 3857174294Sobrien * error code if failure 3858174294Sobrien * 3859174294Sobrien * Timestamps: 3860174294Sobrien * tdvp - ctime|mtime updated 3861174294Sobrien * svp - ctime updated 3862174294Sobrien */ 3863174294Sobrien/* ARGSUSED */ 3864174294Sobrienstatic int 3865174294Sobrienzfs_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr, 3866174294Sobrien caller_context_t *ct, int flags) 3867174294Sobrien{ 3868174294Sobrien znode_t *dzp = VTOZ(tdvp); 3869174294Sobrien znode_t *tzp, *szp; 3870174294Sobrien zfsvfs_t *zfsvfs = dzp->z_zfsvfs; 3871174294Sobrien zilog_t *zilog; 3872174294Sobrien zfs_dirlock_t *dl; 3873174294Sobrien dmu_tx_t *tx; 3874174294Sobrien vnode_t *realvp; 3875174294Sobrien int error; 3876174294Sobrien int zf = ZNEW; 3877174294Sobrien uint64_t parent; 3878174294Sobrien uid_t owner; 3879174294Sobrien 3880174294Sobrien ASSERT(tdvp->v_type == VDIR); 3881174294Sobrien 3882174294Sobrien ZFS_ENTER(zfsvfs); 3883174294Sobrien ZFS_VERIFY_ZP(dzp); 3884174294Sobrien zilog = zfsvfs->z_log; 3885174294Sobrien 3886174294Sobrien if (VOP_REALVP(svp, &realvp, ct) == 0) 3887174294Sobrien svp = realvp; 3888174294Sobrien 3889174294Sobrien /* 3890174294Sobrien * POSIX dictates that we return EPERM here. 3891174294Sobrien * Better choices include ENOTSUP or EISDIR. 3892174294Sobrien */ 3893174294Sobrien if (svp->v_type == VDIR) { 3894174294Sobrien ZFS_EXIT(zfsvfs); 3895174294Sobrien return (EPERM); 3896174294Sobrien } 3897174294Sobrien 3898174294Sobrien if (svp->v_vfsp != tdvp->v_vfsp || zfsctl_is_node(svp)) { 3899174294Sobrien ZFS_EXIT(zfsvfs); 3900174294Sobrien return (EXDEV); 3901174294Sobrien } 3902174294Sobrien 3903174294Sobrien szp = VTOZ(svp); 3904174294Sobrien ZFS_VERIFY_ZP(szp); 3905174294Sobrien 3906174294Sobrien /* Prevent links to .zfs/shares files */ 3907174294Sobrien 3908174294Sobrien if (szp->z_phys->zp_parent == zfsvfs->z_shares_dir) { 3909174294Sobrien ZFS_EXIT(zfsvfs); 3910174294Sobrien return (EPERM); 3911174294Sobrien } 3912174294Sobrien 3913174294Sobrien if (zfsvfs->z_utf8 && u8_validate(name, 3914174294Sobrien strlen(name), NULL, U8_VALIDATE_ENTIRE, &error) < 0) { 3915174294Sobrien ZFS_EXIT(zfsvfs); 3916174294Sobrien return (EILSEQ); 3917174294Sobrien } 3918174294Sobrien if (flags & FIGNORECASE) 3919174294Sobrien zf |= ZCILOOK; 3920174294Sobrien 3921174294Sobrien /* 3922174294Sobrien * We do not support links between attributes and non-attributes 3923174294Sobrien * because of the potential security risk of creating links 3924174294Sobrien * into "normal" file space in order to circumvent restrictions 3925174294Sobrien * imposed in attribute space. 3926174294Sobrien */ 3927174294Sobrien if ((szp->z_phys->zp_flags & ZFS_XATTR) != 3928174294Sobrien (dzp->z_phys->zp_flags & ZFS_XATTR)) { 3929174294Sobrien ZFS_EXIT(zfsvfs); 3930174294Sobrien return (EINVAL); 3931174294Sobrien } 3932174294Sobrien 3933174294Sobrien 3934174294Sobrien owner = zfs_fuid_map_id(zfsvfs, szp->z_phys->zp_uid, cr, ZFS_OWNER); 3935174294Sobrien if (owner != crgetuid(cr) && 3936174294Sobrien secpolicy_basic_link(svp, cr) != 0) { 3937174294Sobrien ZFS_EXIT(zfsvfs); 3938174294Sobrien return (EPERM); 3939174294Sobrien } 3940174294Sobrien 3941174294Sobrien if (error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr)) { 3942174294Sobrien ZFS_EXIT(zfsvfs); 3943174294Sobrien return (error); 3944174294Sobrien } 3945174294Sobrien 3946174294Sobrientop: 3947174294Sobrien /* 3948174294Sobrien * Attempt to lock directory; fail if entry already exists. 3949174294Sobrien */ 3950174294Sobrien error = zfs_dirent_lock(&dl, dzp, name, &tzp, zf, NULL, NULL); 3951174294Sobrien if (error) { 3952174294Sobrien ZFS_EXIT(zfsvfs); 3953174294Sobrien return (error); 3954174294Sobrien } 3955174294Sobrien 3956174294Sobrien tx = dmu_tx_create(zfsvfs->z_os); 3957174294Sobrien dmu_tx_hold_bonus(tx, szp->z_id); 3958174294Sobrien dmu_tx_hold_zap(tx, dzp->z_id, TRUE, name); 3959174294Sobrien error = dmu_tx_assign(tx, TXG_NOWAIT); 3960174294Sobrien if (error) { 3961174294Sobrien zfs_dirent_unlock(dl); 3962174294Sobrien if (error == ERESTART) { 3963174294Sobrien dmu_tx_wait(tx); 3964174294Sobrien dmu_tx_abort(tx); 3965174294Sobrien goto top; 3966174294Sobrien } 3967174294Sobrien dmu_tx_abort(tx); 3968174294Sobrien ZFS_EXIT(zfsvfs); 3969174294Sobrien return (error); 3970174294Sobrien } 3971174294Sobrien 3972174294Sobrien error = zfs_link_create(dl, szp, tx, 0); 3973174294Sobrien 3974174294Sobrien if (error == 0) { 3975174294Sobrien uint64_t txtype = TX_LINK; 3976174294Sobrien if (flags & FIGNORECASE) 3977174294Sobrien txtype |= TX_CI; 3978174294Sobrien zfs_log_link(zilog, tx, txtype, dzp, szp, name); 3979174294Sobrien } 3980174294Sobrien 3981174294Sobrien dmu_tx_commit(tx); 3982174294Sobrien 3983174294Sobrien zfs_dirent_unlock(dl); 3984174294Sobrien 3985174294Sobrien if (error == 0) { 3986174294Sobrien vnevent_link(svp, ct); 3987174294Sobrien } 3988174294Sobrien 3989174294Sobrien ZFS_EXIT(zfsvfs); 3990174294Sobrien return (error); 3991174294Sobrien} 3992174294Sobrien 3993174294Sobrien/*ARGSUSED*/ 3994174294Sobrienvoid 3995174294Sobrienzfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct) 3996174294Sobrien{ 3997174294Sobrien znode_t *zp = VTOZ(vp); 3998174294Sobrien zfsvfs_t *zfsvfs = zp->z_zfsvfs; 3999174294Sobrien int error; 4000174294Sobrien 4001174294Sobrien rw_enter(&zfsvfs->z_teardown_inactive_lock, RW_READER); 4002174294Sobrien if (zp->z_dbuf == NULL) { 4003174294Sobrien /* 4004174294Sobrien * The fs has been unmounted, or we did a 4005174294Sobrien * suspend/resume and this file no longer exists. 4006174294Sobrien */ 4007174294Sobrien VI_LOCK(vp); 4008174294Sobrien vp->v_count = 0; /* count arrives as 1 */ 4009174294Sobrien VI_UNLOCK(vp); 4010174294Sobrien vrecycle(vp, curthread); 4011174294Sobrien rw_exit(&zfsvfs->z_teardown_inactive_lock); 4012174294Sobrien return; 4013174294Sobrien } 4014174294Sobrien 4015174294Sobrien if (zp->z_atime_dirty && zp->z_unlinked == 0) { 4016174294Sobrien dmu_tx_t *tx = dmu_tx_create(zfsvfs->z_os); 4017174294Sobrien 4018174294Sobrien dmu_tx_hold_bonus(tx, zp->z_id); 4019174294Sobrien error = dmu_tx_assign(tx, TXG_WAIT); 4020174294Sobrien if (error) { 4021174294Sobrien dmu_tx_abort(tx); 4022174294Sobrien } else { 4023174294Sobrien dmu_buf_will_dirty(zp->z_dbuf, tx); 4024174294Sobrien mutex_enter(&zp->z_lock); 4025174294Sobrien zp->z_atime_dirty = 0; 4026174294Sobrien mutex_exit(&zp->z_lock); 4027174294Sobrien dmu_tx_commit(tx); 4028174294Sobrien } 4029174294Sobrien } 4030174294Sobrien 4031174294Sobrien zfs_zinactive(zp); 4032174294Sobrien rw_exit(&zfsvfs->z_teardown_inactive_lock); 4033174294Sobrien} 4034174294Sobrien 4035174294SobrienCTASSERT(sizeof(struct zfid_short) <= sizeof(struct fid)); 4036174294SobrienCTASSERT(sizeof(struct zfid_long) <= sizeof(struct fid)); 4037174294Sobrien 4038174294Sobrien/*ARGSUSED*/ 4039174294Sobrienstatic int 4040174294Sobrienzfs_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct) 4041174294Sobrien{ 4042174294Sobrien znode_t *zp = VTOZ(vp); 4043174294Sobrien zfsvfs_t *zfsvfs = zp->z_zfsvfs; 4044174294Sobrien uint32_t gen; 4045174294Sobrien uint64_t object = zp->z_id; 4046174294Sobrien zfid_short_t *zfid; 4047174294Sobrien int size, i; 4048174294Sobrien 4049174294Sobrien ZFS_ENTER(zfsvfs); 4050174294Sobrien ZFS_VERIFY_ZP(zp); 4051174294Sobrien gen = (uint32_t)zp->z_gen; 4052174294Sobrien 4053174294Sobrien size = (zfsvfs->z_parent != zfsvfs) ? LONG_FID_LEN : SHORT_FID_LEN; 4054174294Sobrien fidp->fid_len = size; 4055174294Sobrien 4056174294Sobrien zfid = (zfid_short_t *)fidp; 4057174294Sobrien 4058174294Sobrien zfid->zf_len = size; 4059174294Sobrien 4060174294Sobrien for (i = 0; i < sizeof (zfid->zf_object); i++) 4061174294Sobrien zfid->zf_object[i] = (uint8_t)(object >> (8 * i)); 4062174294Sobrien 4063174294Sobrien /* Must have a non-zero generation number to distinguish from .zfs */ 4064174294Sobrien if (gen == 0) 4065174294Sobrien gen = 1; 4066174294Sobrien for (i = 0; i < sizeof (zfid->zf_gen); i++) 4067174294Sobrien zfid->zf_gen[i] = (uint8_t)(gen >> (8 * i)); 4068174294Sobrien 4069174294Sobrien if (size == LONG_FID_LEN) { 4070174294Sobrien uint64_t objsetid = dmu_objset_id(zfsvfs->z_os); 4071174294Sobrien zfid_long_t *zlfid; 4072174294Sobrien 4073174294Sobrien zlfid = (zfid_long_t *)fidp; 4074174294Sobrien 4075174294Sobrien for (i = 0; i < sizeof (zlfid->zf_setid); i++) 4076174294Sobrien zlfid->zf_setid[i] = (uint8_t)(objsetid >> (8 * i)); 4077174294Sobrien 4078174294Sobrien /* XXX - this should be the generation number for the objset */ 4079174294Sobrien for (i = 0; i < sizeof (zlfid->zf_setgen); i++) 4080174294Sobrien zlfid->zf_setgen[i] = 0; 4081174294Sobrien } 4082174294Sobrien 4083174294Sobrien ZFS_EXIT(zfsvfs); 4084174294Sobrien return (0); 4085174294Sobrien} 4086174294Sobrien 4087174294Sobrienstatic int 4088174294Sobrienzfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr, 4089174294Sobrien caller_context_t *ct) 4090174294Sobrien{ 4091174294Sobrien znode_t *zp, *xzp; 4092174294Sobrien zfsvfs_t *zfsvfs; 4093174294Sobrien zfs_dirlock_t *dl; 4094174294Sobrien int error; 4095174294Sobrien 4096174294Sobrien switch (cmd) { 4097174294Sobrien case _PC_LINK_MAX: 4098174294Sobrien *valp = INT_MAX; 4099174294Sobrien return (0); 4100174294Sobrien 4101174294Sobrien case _PC_FILESIZEBITS: 4102174294Sobrien *valp = 64; 4103174294Sobrien return (0); 4104174294Sobrien 4105174294Sobrien#if 0 4106174294Sobrien case _PC_XATTR_EXISTS: 4107174294Sobrien zp = VTOZ(vp); 4108174294Sobrien zfsvfs = zp->z_zfsvfs; 4109174294Sobrien ZFS_ENTER(zfsvfs); 4110174294Sobrien ZFS_VERIFY_ZP(zp); 4111174294Sobrien *valp = 0; 4112174294Sobrien error = zfs_dirent_lock(&dl, zp, "", &xzp, 4113174294Sobrien ZXATTR | ZEXISTS | ZSHARED, NULL, NULL); 4114174294Sobrien if (error == 0) { 4115174294Sobrien zfs_dirent_unlock(dl); 4116174294Sobrien if (!zfs_dirempty(xzp)) 4117174294Sobrien *valp = 1; 4118174294Sobrien VN_RELE(ZTOV(xzp)); 4119174294Sobrien } else if (error == ENOENT) { 4120174294Sobrien /* 4121174294Sobrien * If there aren't extended attributes, it's the 4122174294Sobrien * same as having zero of them. 4123174294Sobrien */ 4124174294Sobrien error = 0; 4125174294Sobrien } 4126174294Sobrien ZFS_EXIT(zfsvfs); 4127174294Sobrien return (error); 4128174294Sobrien#endif 4129174294Sobrien 4130174294Sobrien case _PC_ACL_EXTENDED: 4131174294Sobrien *valp = 0; 4132174294Sobrien return (0); 4133174294Sobrien 4134174294Sobrien case _PC_ACL_NFS4: 4135174294Sobrien *valp = 1; 4136174294Sobrien return (0); 4137174294Sobrien 4138174294Sobrien case _PC_ACL_PATH_MAX: 4139174294Sobrien *valp = ACL_MAX_ENTRIES; 4140174294Sobrien return (0); 4141174294Sobrien 4142174294Sobrien case _PC_MIN_HOLE_SIZE: 4143174294Sobrien *valp = (int)SPA_MINBLOCKSIZE; 4144174294Sobrien return (0); 4145174294Sobrien 4146174294Sobrien default: 4147174294Sobrien return (EOPNOTSUPP); 4148174294Sobrien } 4149174294Sobrien} 4150174294Sobrien 4151174294Sobrien/*ARGSUSED*/ 4152174294Sobrienstatic int 4153174294Sobrienzfs_getsecattr(vnode_t *vp, vsecattr_t *vsecp, int flag, cred_t *cr, 4154174294Sobrien caller_context_t *ct) 4155174294Sobrien{ 4156174294Sobrien znode_t *zp = VTOZ(vp); 4157174294Sobrien zfsvfs_t *zfsvfs = zp->z_zfsvfs; 4158174294Sobrien int error; 4159174294Sobrien boolean_t skipaclchk = (flag & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE; 4160174294Sobrien 4161174294Sobrien ZFS_ENTER(zfsvfs); 4162174294Sobrien ZFS_VERIFY_ZP(zp); 4163174294Sobrien error = zfs_getacl(zp, vsecp, skipaclchk, cr); 4164174294Sobrien ZFS_EXIT(zfsvfs); 4165174294Sobrien 4166174294Sobrien return (error); 4167174294Sobrien} 4168174294Sobrien 4169174294Sobrien/*ARGSUSED*/ 4170174294Sobrienstatic int 4171174294Sobrienzfs_setsecattr(vnode_t *vp, vsecattr_t *vsecp, int flag, cred_t *cr, 4172119679Smbr caller_context_t *ct) 4173119679Smbr{ 4174119679Smbr znode_t *zp = VTOZ(vp); 4175119679Smbr zfsvfs_t *zfsvfs = zp->z_zfsvfs; 4176119679Smbr int error; 4177119679Smbr boolean_t skipaclchk = (flag & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE; 4178119679Smbr 4179119679Smbr ZFS_ENTER(zfsvfs); 4180119679Smbr ZFS_VERIFY_ZP(zp); 4181174294Sobrien error = zfs_setacl(zp, vsecp, skipaclchk, cr); 4182119679Smbr ZFS_EXIT(zfsvfs); 4183119679Smbr return (error); 4184119679Smbr} 4185119679Smbr 4186174294Sobrienstatic int 4187174294Sobrienzfs_freebsd_open(ap) 4188174294Sobrien struct vop_open_args /* { 4189174294Sobrien struct vnode *a_vp; 4190119679Smbr int a_mode; 4191119679Smbr struct ucred *a_cred; 4192119679Smbr struct thread *a_td; 4193119679Smbr } */ *ap; 4194119679Smbr{ 4195119679Smbr vnode_t *vp = ap->a_vp; 4196119679Smbr znode_t *zp = VTOZ(vp); 4197174294Sobrien int error; 4198174294Sobrien 4199119679Smbr error = zfs_open(&vp, ap->a_mode, ap->a_cred, NULL); 4200119679Smbr if (error == 0) 4201174294Sobrien vnode_create_vobject(vp, zp->z_phys->zp_size, ap->a_td); 4202174294Sobrien return (error); 4203174294Sobrien} 4204174294Sobrien 4205174294Sobrienstatic int 4206119679Smbrzfs_freebsd_close(ap) 4207119679Smbr struct vop_close_args /* { 4208119679Smbr struct vnode *a_vp; 4209119679Smbr int a_fflag; 4210119679Smbr struct ucred *a_cred; 4211119679Smbr struct thread *a_td; 4212119679Smbr } */ *ap; 4213119679Smbr{ 4214174294Sobrien 4215119679Smbr return (zfs_close(ap->a_vp, ap->a_fflag, 0, 0, ap->a_cred, NULL)); 4216119679Smbr} 4217119679Smbr 4218119679Smbrstatic int 4219119679Smbrzfs_freebsd_ioctl(ap) 4220119679Smbr struct vop_ioctl_args /* { 4221119679Smbr struct vnode *a_vp; 4222119679Smbr u_long a_command; 4223119679Smbr caddr_t a_data; 4224119679Smbr int a_fflag; 4225119679Smbr struct ucred *cred; 4226119679Smbr struct thread *td; 4227119679Smbr } */ *ap; 4228119679Smbr{ 4229119679Smbr 4230119679Smbr return (zfs_ioctl(ap->a_vp, ap->a_command, (intptr_t)ap->a_data, 4231174294Sobrien ap->a_fflag, ap->a_cred, NULL, NULL)); 4232174294Sobrien} 4233174294Sobrien 4234174294Sobrienstatic int 4235174294Sobrienzfs_freebsd_read(ap) 4236119679Smbr struct vop_read_args /* { 4237119679Smbr struct vnode *a_vp; 4238119679Smbr struct uio *a_uio; 4239119679Smbr int a_ioflag; 4240119679Smbr struct ucred *a_cred; 4241119679Smbr } */ *ap; 4242119679Smbr{ 4243119679Smbr 4244119679Smbr return (zfs_read(ap->a_vp, ap->a_uio, ap->a_ioflag, ap->a_cred, NULL)); 4245119679Smbr} 4246119679Smbr 4247174294Sobrienstatic int 4248174294Sobrienzfs_freebsd_write(ap) 4249174294Sobrien struct vop_write_args /* { 4250174294Sobrien struct vnode *a_vp; 4251174294Sobrien struct uio *a_uio; 4252174294Sobrien int a_ioflag; 4253174294Sobrien struct ucred *a_cred; 4254119679Smbr } */ *ap; 4255119679Smbr{ 4256119679Smbr 4257119679Smbr if (vn_rlimit_fsize(ap->a_vp, ap->a_uio, ap->a_uio->uio_td)) 4258119679Smbr return (EFBIG); 4259119679Smbr 4260119679Smbr return (zfs_write(ap->a_vp, ap->a_uio, ap->a_ioflag, ap->a_cred, NULL)); 4261119679Smbr} 4262119679Smbr 4263119679Smbrstatic int 4264119679Smbrzfs_freebsd_access(ap) 4265119679Smbr struct vop_access_args /* { 4266119679Smbr struct vnode *a_vp; 4267119679Smbr accmode_t a_accmode; 4268119679Smbr struct ucred *a_cred; 4269119679Smbr struct thread *a_td; 4270119679Smbr } */ *ap; 4271119679Smbr{ 4272119679Smbr vnode_t *vp = ap->a_vp; 4273174294Sobrien znode_t *zp = VTOZ(vp); 4274174294Sobrien znode_phys_t *zphys = zp->z_phys; 4275174294Sobrien accmode_t accmode; 4276174294Sobrien int error = 0; 4277174294Sobrien 4278174294Sobrien /* 4279174294Sobrien * ZFS itself only knowns about VREAD, VWRITE, VEXEC and VAPPEND, 4280174294Sobrien */ 4281174294Sobrien accmode = ap->a_accmode & (VREAD|VWRITE|VEXEC|VAPPEND); 4282174294Sobrien if (accmode != 0) 4283174294Sobrien error = zfs_access(ap->a_vp, accmode, 0, ap->a_cred, NULL); 4284174294Sobrien 4285174294Sobrien /* 4286174294Sobrien * VADMIN has to be handled by vaccess(). 4287174294Sobrien */ 4288174294Sobrien if (error == 0) { 4289174294Sobrien accmode = ap->a_accmode & ~(VREAD|VWRITE|VEXEC|VAPPEND); 4290174294Sobrien if (accmode != 0) { 4291174294Sobrien error = vaccess(vp->v_type, zphys->zp_mode, 4292174294Sobrien zphys->zp_uid, zphys->zp_gid, accmode, ap->a_cred, 4293174294Sobrien NULL); 4294174294Sobrien } 4295174294Sobrien } 4296174294Sobrien 4297174294Sobrien /* 4298174294Sobrien * For VEXEC, ensure that at least one execute bit is set for 4299174294Sobrien * non-directories. 4300174294Sobrien */ 4301174294Sobrien if (error == 0 && (ap->a_accmode & VEXEC) != 0 && vp->v_type != VDIR && 4302174294Sobrien (zphys->zp_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0) 4303174294Sobrien error = EACCES; 4304174294Sobrien 4305174294Sobrien return (error); 4306174294Sobrien} 4307174294Sobrien 4308174294Sobrienstatic int 4309174294Sobrienzfs_freebsd_lookup(ap) 4310174294Sobrien struct vop_lookup_args /* { 4311174294Sobrien struct vnode *a_dvp; 4312174294Sobrien struct vnode **a_vpp; 4313174294Sobrien struct componentname *a_cnp; 4314174294Sobrien } */ *ap; 4315174294Sobrien{ 4316174294Sobrien struct componentname *cnp = ap->a_cnp; 4317174294Sobrien char nm[NAME_MAX + 1]; 4318174294Sobrien 4319174294Sobrien ASSERT(cnp->cn_namelen < sizeof(nm)); 4320174294Sobrien strlcpy(nm, cnp->cn_nameptr, MIN(cnp->cn_namelen + 1, sizeof(nm))); 4321174294Sobrien 4322174294Sobrien return (zfs_lookup(ap->a_dvp, nm, ap->a_vpp, cnp, cnp->cn_nameiop, 4323174294Sobrien cnp->cn_cred, cnp->cn_thread, 0)); 4324174294Sobrien} 4325174294Sobrien 4326174294Sobrienstatic int 4327174294Sobrienzfs_freebsd_create(ap) 4328174294Sobrien struct vop_create_args /* { 4329174294Sobrien struct vnode *a_dvp; 4330174294Sobrien struct vnode **a_vpp; 4331174294Sobrien struct componentname *a_cnp; 4332174294Sobrien struct vattr *a_vap; 4333174294Sobrien } */ *ap; 4334174294Sobrien{ 4335174294Sobrien struct componentname *cnp = ap->a_cnp; 4336174294Sobrien vattr_t *vap = ap->a_vap; 4337174294Sobrien int mode; 4338174294Sobrien 4339174294Sobrien ASSERT(cnp->cn_flags & SAVENAME); 4340174294Sobrien 4341174294Sobrien vattr_init_mask(vap); 4342174294Sobrien mode = vap->va_mode & ALLPERMS; 4343174294Sobrien 4344174294Sobrien return (zfs_create(ap->a_dvp, cnp->cn_nameptr, vap, !EXCL, mode, 4345174294Sobrien ap->a_vpp, cnp->cn_cred, cnp->cn_thread)); 4346174294Sobrien} 4347174294Sobrien 4348174294Sobrienstatic int 4349174294Sobrienzfs_freebsd_remove(ap) 4350174294Sobrien struct vop_remove_args /* { 4351174294Sobrien struct vnode *a_dvp; 4352174294Sobrien struct vnode *a_vp; 4353174294Sobrien struct componentname *a_cnp; 4354174294Sobrien } */ *ap; 4355174294Sobrien{ 4356174294Sobrien 4357174294Sobrien ASSERT(ap->a_cnp->cn_flags & SAVENAME); 4358174294Sobrien 4359174294Sobrien return (zfs_remove(ap->a_dvp, ap->a_cnp->cn_nameptr, 4360174294Sobrien ap->a_cnp->cn_cred, NULL, 0)); 4361174294Sobrien} 4362174294Sobrien 4363174294Sobrienstatic int 4364174294Sobrienzfs_freebsd_mkdir(ap) 4365174294Sobrien struct vop_mkdir_args /* { 4366174294Sobrien struct vnode *a_dvp; 4367174294Sobrien struct vnode **a_vpp; 4368174294Sobrien struct componentname *a_cnp; 4369174294Sobrien struct vattr *a_vap; 4370174294Sobrien } */ *ap; 4371174294Sobrien{ 4372174294Sobrien vattr_t *vap = ap->a_vap; 4373174294Sobrien 4374174294Sobrien ASSERT(ap->a_cnp->cn_flags & SAVENAME); 4375174294Sobrien 4376174294Sobrien vattr_init_mask(vap); 4377174294Sobrien 4378174294Sobrien return (zfs_mkdir(ap->a_dvp, ap->a_cnp->cn_nameptr, vap, ap->a_vpp, 4379174294Sobrien ap->a_cnp->cn_cred, NULL, 0, NULL)); 4380174294Sobrien} 4381174294Sobrien 4382174294Sobrienstatic int 4383174294Sobrienzfs_freebsd_rmdir(ap) 4384174294Sobrien struct vop_rmdir_args /* { 4385174294Sobrien struct vnode *a_dvp; 4386174294Sobrien struct vnode *a_vp; 4387174294Sobrien struct componentname *a_cnp; 4388174294Sobrien } */ *ap; 4389174294Sobrien{ 4390174294Sobrien struct componentname *cnp = ap->a_cnp; 4391174294Sobrien 4392174294Sobrien ASSERT(cnp->cn_flags & SAVENAME); 4393174294Sobrien 4394174294Sobrien return (zfs_rmdir(ap->a_dvp, cnp->cn_nameptr, NULL, cnp->cn_cred, NULL, 0)); 4395174294Sobrien} 4396174294Sobrien 4397174294Sobrienstatic int 4398174294Sobrienzfs_freebsd_readdir(ap) 4399174294Sobrien struct vop_readdir_args /* { 4400174294Sobrien struct vnode *a_vp; 4401174294Sobrien struct uio *a_uio; 4402174294Sobrien struct ucred *a_cred; 4403174294Sobrien int *a_eofflag; 4404174294Sobrien int *a_ncookies; 4405174294Sobrien u_long **a_cookies; 4406174294Sobrien } */ *ap; 4407174294Sobrien{ 4408174294Sobrien 4409174294Sobrien return (zfs_readdir(ap->a_vp, ap->a_uio, ap->a_cred, ap->a_eofflag, 4410174294Sobrien ap->a_ncookies, ap->a_cookies)); 4411174294Sobrien} 4412174294Sobrien 4413174294Sobrienstatic int 4414174294Sobrienzfs_freebsd_fsync(ap) 4415174294Sobrien struct vop_fsync_args /* { 4416174294Sobrien struct vnode *a_vp; 4417174294Sobrien int a_waitfor; 4418174294Sobrien struct thread *a_td; 4419174294Sobrien } */ *ap; 4420174294Sobrien{ 4421174294Sobrien 4422174294Sobrien vop_stdfsync(ap); 4423174294Sobrien return (zfs_fsync(ap->a_vp, 0, ap->a_td->td_ucred, NULL)); 4424174294Sobrien} 4425174294Sobrien 4426174294Sobrienstatic int 4427174294Sobrienzfs_freebsd_getattr(ap) 4428174294Sobrien struct vop_getattr_args /* { 4429174294Sobrien struct vnode *a_vp; 4430174294Sobrien struct vattr *a_vap; 4431174294Sobrien struct ucred *a_cred; 4432174294Sobrien struct thread *a_td; 4433174294Sobrien } */ *ap; 4434174294Sobrien{ 4435174294Sobrien vattr_t *vap = ap->a_vap; 4436174294Sobrien xvattr_t xvap; 4437174294Sobrien u_long fflags = 0; 4438174294Sobrien int error; 4439174294Sobrien 4440174294Sobrien xva_init(&xvap); 4441174294Sobrien xvap.xva_vattr = *vap; 4442174294Sobrien xvap.xva_vattr.va_mask |= AT_XVATTR; 4443174294Sobrien 4444174294Sobrien /* Convert chflags into ZFS-type flags. */ 4445174294Sobrien /* XXX: what about SF_SETTABLE?. */ 4446174294Sobrien XVA_SET_REQ(&xvap, XAT_IMMUTABLE); 4447174294Sobrien XVA_SET_REQ(&xvap, XAT_APPENDONLY); 4448174294Sobrien XVA_SET_REQ(&xvap, XAT_NOUNLINK); 4449174294Sobrien XVA_SET_REQ(&xvap, XAT_NODUMP); 4450174294Sobrien error = zfs_getattr(ap->a_vp, (vattr_t *)&xvap, 0, ap->a_cred, NULL); 4451174294Sobrien if (error != 0) 4452174294Sobrien return (error); 4453119679Smbr 4454119679Smbr /* Convert ZFS xattr into chflags. */ 4455119679Smbr#define FLAG_CHECK(fflag, xflag, xfield) do { \ 4456119679Smbr if (XVA_ISSET_RTN(&xvap, (xflag)) && (xfield) != 0) \ 4457119679Smbr fflags |= (fflag); \ 4458119679Smbr} while (0) 4459119679Smbr FLAG_CHECK(SF_IMMUTABLE, XAT_IMMUTABLE, 4460174294Sobrien xvap.xva_xoptattrs.xoa_immutable); 4461119679Smbr FLAG_CHECK(SF_APPEND, XAT_APPENDONLY, 4462174294Sobrien xvap.xva_xoptattrs.xoa_appendonly); 4463119679Smbr FLAG_CHECK(SF_NOUNLINK, XAT_NOUNLINK, 4464174294Sobrien xvap.xva_xoptattrs.xoa_nounlink); 4465174294Sobrien FLAG_CHECK(UF_NODUMP, XAT_NODUMP, 4466119679Smbr xvap.xva_xoptattrs.xoa_nodump); 4467174294Sobrien#undef FLAG_CHECK 4468119679Smbr *vap = xvap.xva_vattr; 4469174294Sobrien vap->va_flags = fflags; 4470174294Sobrien return (0); 4471174294Sobrien} 4472174294Sobrien 4473174294Sobrienstatic int 4474174294Sobrienzfs_freebsd_setattr(ap) 4475174294Sobrien struct vop_setattr_args /* { 4476174294Sobrien struct vnode *a_vp; 4477174294Sobrien struct vattr *a_vap; 4478174294Sobrien struct ucred *a_cred; 4479174294Sobrien struct thread *a_td; 4480119679Smbr } */ *ap; 4481119679Smbr{ 4482119679Smbr vnode_t *vp = ap->a_vp; 4483174294Sobrien vattr_t *vap = ap->a_vap; 4484174294Sobrien cred_t *cred = ap->a_cred; 4485174294Sobrien xvattr_t xvap; 4486174294Sobrien u_long fflags; 4487174294Sobrien uint64_t zflags; 4488174294Sobrien 4489174294Sobrien vattr_init_mask(vap); 4490174294Sobrien vap->va_mask &= ~AT_NOSET; 4491174294Sobrien 4492174294Sobrien xva_init(&xvap); 4493174294Sobrien xvap.xva_vattr = *vap; 4494174294Sobrien 4495174294Sobrien zflags = VTOZ(vp)->z_phys->zp_flags; 4496174294Sobrien 4497174294Sobrien if (vap->va_flags != VNOVAL) { 4498174294Sobrien zfsvfs_t *zfsvfs = VTOZ(vp)->z_zfsvfs; 4499174294Sobrien int error; 4500174294Sobrien 4501174294Sobrien if (zfsvfs->z_use_fuids == B_FALSE) 4502119679Smbr return (EOPNOTSUPP); 4503119679Smbr 4504119679Smbr fflags = vap->va_flags; 4505119679Smbr if ((fflags & ~(SF_IMMUTABLE|SF_APPEND|SF_NOUNLINK|UF_NODUMP)) != 0) 4506119679Smbr return (EOPNOTSUPP); 4507174294Sobrien /* 4508174294Sobrien * Unprivileged processes are not permitted to unset system 4509174294Sobrien * flags, or modify flags if any system flags are set. 4510174294Sobrien * Privileged non-jail processes may not modify system flags 4511174294Sobrien * if securelevel > 0 and any existing system flags are set. 4512119679Smbr * Privileged jail processes behave like privileged non-jail 4513119679Smbr * processes if the security.jail.chflags_allowed sysctl is 4514119679Smbr * is non-zero; otherwise, they behave like unprivileged 4515119679Smbr * processes. 4516119679Smbr */ 4517119679Smbr if (secpolicy_fs_owner(vp->v_mount, cred) == 0 || 4518119679Smbr priv_check_cred(cred, PRIV_VFS_SYSFLAGS, 0) == 0) { 4519119679Smbr if (zflags & 4520119679Smbr (ZFS_IMMUTABLE | ZFS_APPENDONLY | ZFS_NOUNLINK)) { 4521119679Smbr error = securelevel_gt(cred, 0); 4522119679Smbr if (error != 0) 4523119679Smbr return (error); 4524119679Smbr } 4525174294Sobrien } else { 4526119679Smbr /* 4527174294Sobrien * Callers may only modify the file flags on objects they 4528174294Sobrien * have VADMIN rights for. 4529174294Sobrien */ 4530119679Smbr if ((error = VOP_ACCESS(vp, VADMIN, cred, curthread)) != 0) 4531174294Sobrien return (error); 4532119679Smbr if (zflags & 4533174294Sobrien (ZFS_IMMUTABLE | ZFS_APPENDONLY | ZFS_NOUNLINK)) { 4534174294Sobrien return (EPERM); 4535174294Sobrien } 4536119679Smbr if (fflags & 4537174294Sobrien (SF_IMMUTABLE | SF_APPEND | SF_NOUNLINK)) { 4538174294Sobrien return (EPERM); 4539174294Sobrien } 4540119679Smbr } 4541119679Smbr 4542174294Sobrien#define FLAG_CHANGE(fflag, zflag, xflag, xfield) do { \ 4543174294Sobrien if (((fflags & (fflag)) && !(zflags & (zflag))) || \ 4544119679Smbr ((zflags & (zflag)) && !(fflags & (fflag)))) { \ 4545174294Sobrien XVA_SET_REQ(&xvap, (xflag)); \ 4546174294Sobrien (xfield) = ((fflags & (fflag)) != 0); \ 4547174294Sobrien } \ 4548174294Sobrien} while (0) 4549174294Sobrien /* Convert chflags into ZFS-type flags. */ 4550174294Sobrien /* XXX: what about SF_SETTABLE?. */ 4551174294Sobrien FLAG_CHANGE(SF_IMMUTABLE, ZFS_IMMUTABLE, XAT_IMMUTABLE, 4552174294Sobrien xvap.xva_xoptattrs.xoa_immutable); 4553174294Sobrien FLAG_CHANGE(SF_APPEND, ZFS_APPENDONLY, XAT_APPENDONLY, 4554174294Sobrien xvap.xva_xoptattrs.xoa_appendonly); 4555174294Sobrien FLAG_CHANGE(SF_NOUNLINK, ZFS_NOUNLINK, XAT_NOUNLINK, 4556174294Sobrien xvap.xva_xoptattrs.xoa_nounlink); 4557174294Sobrien FLAG_CHANGE(UF_NODUMP, ZFS_NODUMP, XAT_NODUMP, 4558174294Sobrien xvap.xva_xoptattrs.xoa_nodump); 4559174294Sobrien#undef FLAG_CHANGE 4560174294Sobrien } 4561174294Sobrien return (zfs_setattr(vp, (vattr_t *)&xvap, 0, cred, NULL)); 4562174294Sobrien} 4563174294Sobrien 4564174294Sobrienstatic int 4565174294Sobrienzfs_freebsd_rename(ap) 4566174294Sobrien struct vop_rename_args /* { 4567174294Sobrien struct vnode *a_fdvp; 4568174294Sobrien struct vnode *a_fvp; 4569174294Sobrien struct componentname *a_fcnp; 4570174294Sobrien struct vnode *a_tdvp; 4571174294Sobrien struct vnode *a_tvp; 4572174294Sobrien struct componentname *a_tcnp; 4573174294Sobrien } */ *ap; 4574174294Sobrien{ 4575174294Sobrien vnode_t *fdvp = ap->a_fdvp; 4576174294Sobrien vnode_t *fvp = ap->a_fvp; 4577174294Sobrien vnode_t *tdvp = ap->a_tdvp; 4578174294Sobrien vnode_t *tvp = ap->a_tvp; 4579174294Sobrien int error; 4580174294Sobrien 4581174294Sobrien ASSERT(ap->a_fcnp->cn_flags & (SAVENAME|SAVESTART)); 4582174294Sobrien ASSERT(ap->a_tcnp->cn_flags & (SAVENAME|SAVESTART)); 4583174294Sobrien 4584174294Sobrien error = zfs_rename(fdvp, ap->a_fcnp->cn_nameptr, tdvp, 4585174294Sobrien ap->a_tcnp->cn_nameptr, ap->a_fcnp->cn_cred, NULL, 0); 4586174294Sobrien 4587174294Sobrien if (tdvp == tvp) 4588174294Sobrien VN_RELE(tdvp); 4589174294Sobrien else 4590174294Sobrien VN_URELE(tdvp); 4591174294Sobrien if (tvp) 4592174294Sobrien VN_URELE(tvp); 4593174294Sobrien VN_RELE(fdvp); 4594174294Sobrien VN_RELE(fvp); 4595174294Sobrien 4596174294Sobrien return (error); 4597174294Sobrien} 4598174294Sobrien 4599119679Smbrstatic int 4600119679Smbrzfs_freebsd_symlink(ap) 4601119679Smbr struct vop_symlink_args /* { 4602119679Smbr struct vnode *a_dvp; 4603119679Smbr struct vnode **a_vpp; 4604119679Smbr struct componentname *a_cnp; 4605119679Smbr struct vattr *a_vap; 4606174294Sobrien char *a_target; 4607174294Sobrien } */ *ap; 4608174294Sobrien{ 4609174294Sobrien struct componentname *cnp = ap->a_cnp; 4610174294Sobrien vattr_t *vap = ap->a_vap; 4611174294Sobrien 4612174294Sobrien ASSERT(cnp->cn_flags & SAVENAME); 4613174294Sobrien 4614174294Sobrien vap->va_type = VLNK; /* FreeBSD: Syscall only sets va_mode. */ 4615174294Sobrien vattr_init_mask(vap); 4616174294Sobrien 4617174294Sobrien return (zfs_symlink(ap->a_dvp, ap->a_vpp, cnp->cn_nameptr, vap, 4618174294Sobrien ap->a_target, cnp->cn_cred, cnp->cn_thread)); 4619174294Sobrien} 4620174294Sobrien 4621174294Sobrienstatic int 4622174294Sobrienzfs_freebsd_readlink(ap) 4623174294Sobrien struct vop_readlink_args /* { 4624174294Sobrien struct vnode *a_vp; 4625174294Sobrien struct uio *a_uio; 4626174294Sobrien struct ucred *a_cred; 4627174294Sobrien } */ *ap; 4628174294Sobrien{ 4629174294Sobrien 4630174294Sobrien return (zfs_readlink(ap->a_vp, ap->a_uio, ap->a_cred, NULL)); 4631174294Sobrien} 4632174294Sobrien 4633119679Smbrstatic int 4634119679Smbrzfs_freebsd_link(ap) 4635119679Smbr struct vop_link_args /* { 4636119679Smbr struct vnode *a_tdvp; 4637119679Smbr struct vnode *a_vp; 4638174294Sobrien struct componentname *a_cnp; 4639119679Smbr } */ *ap; 4640174294Sobrien{ 4641119679Smbr struct componentname *cnp = ap->a_cnp; 4642174294Sobrien 4643174294Sobrien ASSERT(cnp->cn_flags & SAVENAME); 4644119679Smbr 4645174294Sobrien return (zfs_link(ap->a_tdvp, ap->a_vp, cnp->cn_nameptr, cnp->cn_cred, NULL, 0)); 4646174294Sobrien} 4647174294Sobrien 4648119679Smbrstatic int 4649174294Sobrienzfs_freebsd_inactive(ap) 4650119679Smbr struct vop_inactive_args /* { 4651174294Sobrien struct vnode *a_vp; 4652174294Sobrien struct thread *a_td; 4653119679Smbr } */ *ap; 4654174294Sobrien{ 4655174294Sobrien vnode_t *vp = ap->a_vp; 4656174294Sobrien 4657174294Sobrien zfs_inactive(vp, ap->a_td->td_ucred, NULL); 4658174294Sobrien return (0); 4659174294Sobrien} 4660174294Sobrien 4661119679Smbrstatic void 4662174294Sobrienzfs_reclaim_complete(void *arg, int pending) 4663174294Sobrien{ 4664119679Smbr znode_t *zp = arg; 4665174294Sobrien zfsvfs_t *zfsvfs = zp->z_zfsvfs; 4666119679Smbr 4667174294Sobrien rw_enter(&zfsvfs->z_teardown_inactive_lock, RW_READER); 4668174294Sobrien if (zp->z_dbuf != NULL) { 4669174294Sobrien ZFS_OBJ_HOLD_ENTER(zfsvfs, zp->z_id); 4670119679Smbr zfs_znode_dmu_fini(zp); 4671174294Sobrien ZFS_OBJ_HOLD_EXIT(zfsvfs, zp->z_id); 4672174294Sobrien } 4673174294Sobrien zfs_znode_free(zp); 4674174294Sobrien rw_exit(&zfsvfs->z_teardown_inactive_lock); 4675174294Sobrien /* 4676119679Smbr * If the file system is being unmounted, there is a process waiting 4677174294Sobrien * for us, wake it up. 4678174294Sobrien */ 4679174294Sobrien if (zfsvfs->z_unmounted) 4680174294Sobrien wakeup_one(zfsvfs); 4681174294Sobrien} 4682174294Sobrien 4683174294Sobrienstatic int 4684174294Sobrienzfs_freebsd_reclaim(ap) 4685174294Sobrien struct vop_reclaim_args /* { 4686174294Sobrien struct vnode *a_vp; 4687174294Sobrien struct thread *a_td; 4688174294Sobrien } */ *ap; 4689174294Sobrien{ 4690174294Sobrien vnode_t *vp = ap->a_vp; 4691174294Sobrien znode_t *zp = VTOZ(vp); 4692174294Sobrien zfsvfs_t *zfsvfs = zp->z_zfsvfs; 4693174294Sobrien 4694174294Sobrien rw_enter(&zfsvfs->z_teardown_inactive_lock, RW_READER); 4695174294Sobrien 4696174294Sobrien ASSERT(zp != NULL); 4697174294Sobrien 4698174294Sobrien /* 4699174294Sobrien * Destroy the vm object and flush associated pages. 4700174294Sobrien */ 4701174294Sobrien vnode_destroy_vobject(vp); 4702174294Sobrien 4703174294Sobrien mutex_enter(&zp->z_lock); 4704174294Sobrien ASSERT(zp->z_phys != NULL); 4705174294Sobrien zp->z_vnode = NULL; 4706174294Sobrien mutex_exit(&zp->z_lock); 4707174294Sobrien 4708174294Sobrien if (zp->z_unlinked) 4709174294Sobrien ; /* Do nothing. */ 4710174294Sobrien else if (zp->z_dbuf == NULL) 4711174294Sobrien zfs_znode_free(zp); 4712174294Sobrien else /* if (!zp->z_unlinked && zp->z_dbuf != NULL) */ { 4713174294Sobrien int locked; 4714174294Sobrien 4715174294Sobrien locked = MUTEX_HELD(ZFS_OBJ_MUTEX(zfsvfs, zp->z_id)) ? 2 : 4716174294Sobrien ZFS_OBJ_HOLD_TRYENTER(zfsvfs, zp->z_id); 4717174294Sobrien if (locked == 0) { 4718174294Sobrien /* 4719174294Sobrien * Lock can't be obtained due to deadlock possibility, 4720174294Sobrien * so defer znode destruction. 4721174294Sobrien */ 4722174294Sobrien TASK_INIT(&zp->z_task, 0, zfs_reclaim_complete, zp); 4723174294Sobrien taskqueue_enqueue(taskqueue_thread, &zp->z_task); 4724174294Sobrien } else { 4725174294Sobrien zfs_znode_dmu_fini(zp); 4726174294Sobrien if (locked == 1) 4727174294Sobrien ZFS_OBJ_HOLD_EXIT(zfsvfs, zp->z_id); 4728174294Sobrien zfs_znode_free(zp); 4729174294Sobrien } 4730174294Sobrien } 4731174294Sobrien VI_LOCK(vp); 4732174294Sobrien vp->v_data = NULL; 4733174294Sobrien ASSERT(vp->v_holdcnt >= 1); 4734174294Sobrien VI_UNLOCK(vp); 4735174294Sobrien rw_exit(&zfsvfs->z_teardown_inactive_lock); 4736174294Sobrien return (0); 4737174294Sobrien} 4738174294Sobrien 4739174294Sobrienstatic int 4740174294Sobrienzfs_freebsd_fid(ap) 4741174294Sobrien struct vop_fid_args /* { 4742174294Sobrien struct vnode *a_vp; 4743174294Sobrien struct fid *a_fid; 4744174294Sobrien } */ *ap; 4745174294Sobrien{ 4746174294Sobrien 4747174294Sobrien return (zfs_fid(ap->a_vp, (void *)ap->a_fid, NULL)); 4748174294Sobrien} 4749174294Sobrien 4750174294Sobrienstatic int 4751174294Sobrienzfs_freebsd_pathconf(ap) 4752174294Sobrien struct vop_pathconf_args /* { 4753174294Sobrien struct vnode *a_vp; 4754174294Sobrien int a_name; 4755174294Sobrien register_t *a_retval; 4756174294Sobrien } */ *ap; 4757174294Sobrien{ 4758174294Sobrien ulong_t val; 4759174294Sobrien int error; 4760174294Sobrien 4761174294Sobrien error = zfs_pathconf(ap->a_vp, ap->a_name, &val, curthread->td_ucred, NULL); 4762174294Sobrien if (error == 0) 4763174294Sobrien *ap->a_retval = val; 4764174294Sobrien else if (error == EOPNOTSUPP) 4765174294Sobrien error = vop_stdpathconf(ap); 4766174294Sobrien return (error); 4767174294Sobrien} 4768174294Sobrien 4769174294Sobrienstatic int 4770174294Sobrienzfs_freebsd_fifo_pathconf(ap) 4771174294Sobrien struct vop_pathconf_args /* { 4772174294Sobrien struct vnode *a_vp; 4773119679Smbr int a_name; 4774119679Smbr register_t *a_retval; 4775174294Sobrien } */ *ap; 4776174294Sobrien{ 4777119679Smbr 4778174294Sobrien switch (ap->a_name) { 4779174294Sobrien case _PC_ACL_EXTENDED: 4780174294Sobrien case _PC_ACL_NFS4: 4781174294Sobrien case _PC_ACL_PATH_MAX: 4782174294Sobrien case _PC_MAC_PRESENT: 4783174294Sobrien return (zfs_freebsd_pathconf(ap)); 4784174294Sobrien default: 4785174294Sobrien return (fifo_specops.vop_pathconf(ap)); 4786174294Sobrien } 4787174294Sobrien} 4788174294Sobrien 4789174294Sobrien/* 4790174294Sobrien * FreeBSD's extended attributes namespace defines file name prefix for ZFS' 4791174294Sobrien * extended attribute name: 4792119679Smbr * 4793174294Sobrien * NAMESPACE PREFIX 4794119679Smbr * system freebsd:system: 4795174294Sobrien * user (none, can be used to access ZFS fsattr(5) attributes 4796174294Sobrien * created on Solaris) 4797174294Sobrien */ 4798174294Sobrienstatic int 4799174294Sobrienzfs_create_attrname(int attrnamespace, const char *name, char *attrname, 4800174294Sobrien size_t size) 4801174294Sobrien{ 4802174294Sobrien const char *namespace, *prefix, *suffix; 4803174294Sobrien 4804174294Sobrien /* We don't allow '/' character in attribute name. */ 4805174294Sobrien if (strchr(name, '/') != NULL) 4806119679Smbr return (EINVAL); 4807119679Smbr /* We don't allow attribute names that start with "freebsd:" string. */ 4808119679Smbr if (strncmp(name, "freebsd:", 8) == 0) 4809119679Smbr return (EINVAL); 4810119679Smbr 4811174294Sobrien bzero(attrname, size); 4812119679Smbr 4813119679Smbr switch (attrnamespace) { 4814119679Smbr case EXTATTR_NAMESPACE_USER: 4815119679Smbr#if 0 4816174294Sobrien prefix = "freebsd:"; 4817174294Sobrien namespace = EXTATTR_NAMESPACE_USER_STRING; 4818174294Sobrien suffix = ":"; 4819174294Sobrien#else 4820174294Sobrien /* 4821174294Sobrien * This is the default namespace by which we can access all 4822174294Sobrien * attributes created on Solaris. 4823174294Sobrien */ 4824174294Sobrien prefix = namespace = suffix = ""; 4825174294Sobrien#endif 4826119679Smbr break; 4827119679Smbr case EXTATTR_NAMESPACE_SYSTEM: 4828174294Sobrien prefix = "freebsd:"; 4829174294Sobrien namespace = EXTATTR_NAMESPACE_SYSTEM_STRING; 4830174294Sobrien suffix = ":"; 4831174294Sobrien break; 4832119679Smbr case EXTATTR_NAMESPACE_EMPTY: 4833119679Smbr default: 4834119679Smbr return (EINVAL); 4835119679Smbr } 4836119679Smbr if (snprintf(attrname, size, "%s%s%s%s", prefix, namespace, suffix, 4837174294Sobrien name) >= size) { 4838174294Sobrien return (ENAMETOOLONG); 4839119679Smbr } 4840119679Smbr return (0); 4841119679Smbr} 4842174294Sobrien 4843174294Sobrien/* 4844119679Smbr * Vnode operating to retrieve a named extended attribute. 4845174294Sobrien */ 4846174294Sobrienstatic int 4847174294Sobrienzfs_getextattr(struct vop_getextattr_args *ap) 4848174294Sobrien/* 4849174294Sobrienvop_getextattr { 4850174294Sobrien IN struct vnode *a_vp; 4851174294Sobrien IN int a_attrnamespace; 4852174294Sobrien IN const char *a_name; 4853174294Sobrien INOUT struct uio *a_uio; 4854174294Sobrien OUT size_t *a_size; 4855174294Sobrien IN struct ucred *a_cred; 4856174294Sobrien IN struct thread *a_td; 4857174294Sobrien}; 4858174294Sobrien*/ 4859174294Sobrien{ 4860174294Sobrien zfsvfs_t *zfsvfs = VTOZ(ap->a_vp)->z_zfsvfs; 4861174294Sobrien struct thread *td = ap->a_td; 4862174294Sobrien struct nameidata nd; 4863174294Sobrien char attrname[255]; 4864174294Sobrien struct vattr va; 4865174294Sobrien vnode_t *xvp = NULL, *vp; 4866174294Sobrien int error, flags; 4867174294Sobrien 4868174294Sobrien error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, 4869174294Sobrien ap->a_cred, ap->a_td, VREAD); 4870174294Sobrien if (error != 0) 4871174294Sobrien return (error); 4872174294Sobrien 4873174294Sobrien error = zfs_create_attrname(ap->a_attrnamespace, ap->a_name, attrname, 4874174294Sobrien sizeof(attrname)); 4875174294Sobrien if (error != 0) 4876174294Sobrien return (error); 4877174294Sobrien 4878174294Sobrien ZFS_ENTER(zfsvfs); 4879174294Sobrien 4880174294Sobrien error = zfs_lookup(ap->a_vp, NULL, &xvp, NULL, 0, ap->a_cred, td, 4881174294Sobrien LOOKUP_XATTR); 4882174294Sobrien if (error != 0) { 4883174294Sobrien ZFS_EXIT(zfsvfs); 4884174294Sobrien return (error); 4885174294Sobrien } 4886174294Sobrien 4887174294Sobrien flags = FREAD; 4888174294Sobrien NDINIT_ATVP(&nd, LOOKUP, NOFOLLOW | MPSAFE, UIO_SYSSPACE, attrname, 4889174294Sobrien xvp, td); 4890174294Sobrien error = vn_open_cred(&nd, &flags, 0, 0, ap->a_cred, NULL); 4891174294Sobrien vp = nd.ni_vp; 4892174294Sobrien NDFREE(&nd, NDF_ONLY_PNBUF); 4893174294Sobrien if (error != 0) { 4894174294Sobrien ZFS_EXIT(zfsvfs); 4895174294Sobrien if (error == ENOENT) 4896174294Sobrien error = ENOATTR; 4897174294Sobrien return (error); 4898174294Sobrien } 4899174294Sobrien 4900174294Sobrien if (ap->a_size != NULL) { 4901174294Sobrien error = VOP_GETATTR(vp, &va, ap->a_cred); 4902174294Sobrien if (error == 0) 4903174294Sobrien *ap->a_size = (size_t)va.va_size; 4904174294Sobrien } else if (ap->a_uio != NULL) 4905174294Sobrien error = VOP_READ(vp, ap->a_uio, IO_UNIT | IO_SYNC, ap->a_cred); 4906174294Sobrien 4907174294Sobrien VOP_UNLOCK(vp, 0); 4908174294Sobrien vn_close(vp, flags, ap->a_cred, td); 4909174294Sobrien ZFS_EXIT(zfsvfs); 4910174294Sobrien 4911174294Sobrien return (error); 4912174294Sobrien} 4913174294Sobrien 4914174294Sobrien/* 4915174294Sobrien * Vnode operation to remove a named attribute. 4916174294Sobrien */ 4917174294Sobrienint 4918174294Sobrienzfs_deleteextattr(struct vop_deleteextattr_args *ap) 4919174294Sobrien/* 4920174294Sobrienvop_deleteextattr { 4921174294Sobrien IN struct vnode *a_vp; 4922174294Sobrien IN int a_attrnamespace; 4923174294Sobrien IN const char *a_name; 4924174294Sobrien IN struct ucred *a_cred; 4925174294Sobrien IN struct thread *a_td; 4926174294Sobrien}; 4927174294Sobrien*/ 4928174294Sobrien{ 4929174294Sobrien zfsvfs_t *zfsvfs = VTOZ(ap->a_vp)->z_zfsvfs; 4930174294Sobrien struct thread *td = ap->a_td; 4931174294Sobrien struct nameidata nd; 4932174294Sobrien char attrname[255]; 4933119679Smbr struct vattr va; 4934119679Smbr vnode_t *xvp = NULL, *vp; 4935119679Smbr int error, flags; 4936119679Smbr 4937174294Sobrien error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, 4938119679Smbr ap->a_cred, ap->a_td, VWRITE); 4939174294Sobrien if (error != 0) 4940119679Smbr return (error); 4941174294Sobrien 4942174294Sobrien error = zfs_create_attrname(ap->a_attrnamespace, ap->a_name, attrname, 4943174294Sobrien sizeof(attrname)); 4944174294Sobrien if (error != 0) 4945174294Sobrien return (error); 4946174294Sobrien 4947174294Sobrien ZFS_ENTER(zfsvfs); 4948174294Sobrien 4949174294Sobrien error = zfs_lookup(ap->a_vp, NULL, &xvp, NULL, 0, ap->a_cred, td, 4950174294Sobrien LOOKUP_XATTR); 4951174294Sobrien if (error != 0) { 4952174294Sobrien ZFS_EXIT(zfsvfs); 4953174294Sobrien return (error); 4954174294Sobrien } 4955174294Sobrien 4956174294Sobrien NDINIT_ATVP(&nd, DELETE, NOFOLLOW | LOCKPARENT | LOCKLEAF | MPSAFE, 4957174294Sobrien UIO_SYSSPACE, attrname, xvp, td); 4958174294Sobrien error = namei(&nd); 4959174294Sobrien vp = nd.ni_vp; 4960174294Sobrien NDFREE(&nd, NDF_ONLY_PNBUF); 4961174294Sobrien if (error != 0) { 4962174294Sobrien ZFS_EXIT(zfsvfs); 4963174294Sobrien if (error == ENOENT) 4964174294Sobrien error = ENOATTR; 4965174294Sobrien return (error); 4966174294Sobrien } 4967174294Sobrien error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd); 4968174294Sobrien 4969174294Sobrien vput(nd.ni_dvp); 4970174294Sobrien if (vp == nd.ni_dvp) 4971174294Sobrien vrele(vp); 4972174294Sobrien else 4973174294Sobrien vput(vp); 4974174294Sobrien ZFS_EXIT(zfsvfs); 4975174294Sobrien 4976174294Sobrien return (error); 4977174294Sobrien} 4978174294Sobrien 4979174294Sobrien/* 4980174294Sobrien * Vnode operation to set a named attribute. 4981174294Sobrien */ 4982174294Sobrienstatic int 4983174294Sobrienzfs_setextattr(struct vop_setextattr_args *ap) 4984174294Sobrien/* 4985174294Sobrienvop_setextattr { 4986174294Sobrien IN struct vnode *a_vp; 4987174294Sobrien IN int a_attrnamespace; 4988174294Sobrien IN const char *a_name; 4989174294Sobrien INOUT struct uio *a_uio; 4990174294Sobrien IN struct ucred *a_cred; 4991174294Sobrien IN struct thread *a_td; 4992174294Sobrien}; 4993174294Sobrien*/ 4994174294Sobrien{ 4995174294Sobrien zfsvfs_t *zfsvfs = VTOZ(ap->a_vp)->z_zfsvfs; 4996174294Sobrien struct thread *td = ap->a_td; 4997174294Sobrien struct nameidata nd; 4998174294Sobrien char attrname[255]; 4999174294Sobrien struct vattr va; 5000174294Sobrien vnode_t *xvp = NULL, *vp; 5001174294Sobrien int error, flags; 5002174294Sobrien 5003119679Smbr error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, 5004119679Smbr ap->a_cred, ap->a_td, VWRITE); 5005119679Smbr if (error != 0) 5006119679Smbr return (error); 5007119679Smbr 5008119679Smbr error = zfs_create_attrname(ap->a_attrnamespace, ap->a_name, attrname, 5009119679Smbr sizeof(attrname)); 5010119679Smbr if (error != 0) 5011119679Smbr return (error); 5012119679Smbr 5013119679Smbr ZFS_ENTER(zfsvfs); 5014119679Smbr 5015119679Smbr error = zfs_lookup(ap->a_vp, NULL, &xvp, NULL, 0, ap->a_cred, td, 5016119679Smbr LOOKUP_XATTR | CREATE_XATTR_DIR); 5017119679Smbr if (error != 0) { 5018119679Smbr ZFS_EXIT(zfsvfs); 5019119679Smbr return (error); 5020174294Sobrien } 5021119679Smbr 5022174294Sobrien flags = FFLAGS(O_WRONLY | O_CREAT); 5023119679Smbr NDINIT_ATVP(&nd, LOOKUP, NOFOLLOW | MPSAFE, UIO_SYSSPACE, attrname, 5024174294Sobrien xvp, td); 5025119679Smbr error = vn_open_cred(&nd, &flags, 0600, 0, ap->a_cred, NULL); 5026174294Sobrien vp = nd.ni_vp; 5027174294Sobrien NDFREE(&nd, NDF_ONLY_PNBUF); 5028174294Sobrien if (error != 0) { 5029174294Sobrien ZFS_EXIT(zfsvfs); 5030174294Sobrien return (error); 5031174294Sobrien } 5032174294Sobrien 5033174294Sobrien VATTR_NULL(&va); 5034119679Smbr va.va_size = 0; 5035119679Smbr error = VOP_SETATTR(vp, &va, ap->a_cred); 5036119679Smbr if (error == 0) 5037119679Smbr VOP_WRITE(vp, ap->a_uio, IO_UNIT | IO_SYNC, ap->a_cred); 5038119679Smbr 5039119679Smbr VOP_UNLOCK(vp, 0); 5040119679Smbr vn_close(vp, flags, ap->a_cred, td); 5041119679Smbr ZFS_EXIT(zfsvfs); 5042119679Smbr 5043119679Smbr return (error); 5044119679Smbr} 5045119679Smbr 5046119679Smbr/* 5047119679Smbr * Vnode operation to retrieve extended attributes on a vnode. 5048119679Smbr */ 5049119679Smbrstatic int 5050119679Smbrzfs_listextattr(struct vop_listextattr_args *ap) 5051119679Smbr/* 5052119679Smbrvop_listextattr { 5053174294Sobrien IN struct vnode *a_vp; 5054174294Sobrien IN int a_attrnamespace; 5055174294Sobrien INOUT struct uio *a_uio; 5056174294Sobrien OUT size_t *a_size; 5057174294Sobrien IN struct ucred *a_cred; 5058174294Sobrien IN struct thread *a_td; 5059119679Smbr}; 5060119679Smbr*/ 5061119679Smbr{ 5062119679Smbr zfsvfs_t *zfsvfs = VTOZ(ap->a_vp)->z_zfsvfs; 5063119679Smbr struct thread *td = ap->a_td; 5064119679Smbr struct nameidata nd; 5065119679Smbr char attrprefix[16]; 5066119679Smbr u_char dirbuf[sizeof(struct dirent)]; 5067119679Smbr struct dirent *dp; 5068119679Smbr struct iovec aiov; 5069174294Sobrien struct uio auio, *uio = ap->a_uio; 5070174294Sobrien size_t *sizep = ap->a_size; 5071174294Sobrien size_t plen; 5072174294Sobrien vnode_t *xvp = NULL, *vp; 5073119679Smbr int done, error, eof, pos; 5074119679Smbr 5075174294Sobrien error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, 5076119679Smbr ap->a_cred, ap->a_td, VREAD); 5077174294Sobrien if (error != 0) 5078174294Sobrien return (error); 5079174294Sobrien 5080174294Sobrien error = zfs_create_attrname(ap->a_attrnamespace, "", attrprefix, 5081174294Sobrien sizeof(attrprefix)); 5082174294Sobrien if (error != 0) 5083174294Sobrien return (error); 5084174294Sobrien plen = strlen(attrprefix); 5085174294Sobrien 5086174294Sobrien ZFS_ENTER(zfsvfs); 5087174294Sobrien 5088174294Sobrien if (sizep != NULL) 5089174294Sobrien *sizep = 0; 5090174294Sobrien 5091174294Sobrien error = zfs_lookup(ap->a_vp, NULL, &xvp, NULL, 0, ap->a_cred, td, 5092174294Sobrien LOOKUP_XATTR); 5093174294Sobrien if (error != 0) { 5094174294Sobrien ZFS_EXIT(zfsvfs); 5095174294Sobrien /* 5096174294Sobrien * ENOATTR means that the EA directory does not yet exist, 5097174294Sobrien * i.e. there are no extended attributes there. 5098174294Sobrien */ 5099174294Sobrien if (error == ENOATTR) 5100174294Sobrien error = 0; 5101174294Sobrien return (error); 5102174294Sobrien } 5103174294Sobrien 5104174294Sobrien NDINIT_ATVP(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKSHARED | MPSAFE, 5105174294Sobrien UIO_SYSSPACE, ".", xvp, td); 5106174294Sobrien error = namei(&nd); 5107174294Sobrien vp = nd.ni_vp; 5108174294Sobrien NDFREE(&nd, NDF_ONLY_PNBUF); 5109174294Sobrien if (error != 0) { 5110174294Sobrien ZFS_EXIT(zfsvfs); 5111174294Sobrien return (error); 5112174294Sobrien } 5113174294Sobrien 5114174294Sobrien auio.uio_iov = &aiov; 5115174294Sobrien auio.uio_iovcnt = 1; 5116174294Sobrien auio.uio_segflg = UIO_SYSSPACE; 5117174294Sobrien auio.uio_td = td; 5118174294Sobrien auio.uio_rw = UIO_READ; 5119174294Sobrien auio.uio_offset = 0; 5120174294Sobrien 5121174294Sobrien do { 5122174294Sobrien u_char nlen; 5123174294Sobrien 5124174294Sobrien aiov.iov_base = (void *)dirbuf; 5125174294Sobrien aiov.iov_len = sizeof(dirbuf); 5126174294Sobrien auio.uio_resid = sizeof(dirbuf); 5127174294Sobrien error = VOP_READDIR(vp, &auio, ap->a_cred, &eof, NULL, NULL); 5128174294Sobrien done = sizeof(dirbuf) - auio.uio_resid; 5129174294Sobrien if (error != 0) 5130174294Sobrien break; 5131174294Sobrien for (pos = 0; pos < done;) { 5132174294Sobrien dp = (struct dirent *)(dirbuf + pos); 5133174294Sobrien pos += dp->d_reclen; 5134174294Sobrien /* 5135174294Sobrien * XXX: Temporarily we also accept DT_UNKNOWN, as this 5136174294Sobrien * is what we get when attribute was created on Solaris. 5137174294Sobrien */ 5138174294Sobrien if (dp->d_type != DT_REG && dp->d_type != DT_UNKNOWN) 5139174294Sobrien continue; 5140174294Sobrien if (plen == 0 && strncmp(dp->d_name, "freebsd:", 8) == 0) 5141174294Sobrien continue; 5142174294Sobrien else if (strncmp(dp->d_name, attrprefix, plen) != 0) 5143174294Sobrien continue; 5144174294Sobrien nlen = dp->d_namlen - plen; 5145174294Sobrien if (sizep != NULL) 5146174294Sobrien *sizep += 1 + nlen; 5147174294Sobrien else if (uio != NULL) { 5148174294Sobrien /* 5149174294Sobrien * Format of extattr name entry is one byte for 5150174294Sobrien * length and the rest for name. 5151174294Sobrien */ 5152174294Sobrien error = uiomove(&nlen, 1, uio->uio_rw, uio); 5153174294Sobrien if (error == 0) { 5154174294Sobrien error = uiomove(dp->d_name + plen, nlen, 5155174294Sobrien uio->uio_rw, uio); 5156119679Smbr } 5157119679Smbr if (error != 0) 5158174294Sobrien break; 5159174294Sobrien } 5160174294Sobrien } 5161174294Sobrien } while (!eof && error == 0); 5162174294Sobrien 5163174294Sobrien vput(vp); 5164174294Sobrien ZFS_EXIT(zfsvfs); 5165174294Sobrien 5166174294Sobrien return (error); 5167174294Sobrien} 5168174294Sobrien 5169174294Sobrienint 5170174294Sobrienzfs_freebsd_getacl(ap) 5171174294Sobrien struct vop_getacl_args /* { 5172174294Sobrien struct vnode *vp; 5173174294Sobrien acl_type_t type; 5174174294Sobrien struct acl *aclp; 5175174294Sobrien struct ucred *cred; 5176174294Sobrien struct thread *td; 5177174294Sobrien } */ *ap; 5178174294Sobrien{ 5179174294Sobrien int error; 5180174294Sobrien vsecattr_t vsecattr; 5181174294Sobrien 5182174294Sobrien if (ap->a_type != ACL_TYPE_NFS4) 5183174294Sobrien return (EINVAL); 5184174294Sobrien 5185174294Sobrien vsecattr.vsa_mask = VSA_ACE | VSA_ACECNT; 5186174294Sobrien if (error = zfs_getsecattr(ap->a_vp, &vsecattr, 0, ap->a_cred, NULL)) 5187174294Sobrien return (error); 5188174294Sobrien 5189174294Sobrien error = acl_from_aces(ap->a_aclp, vsecattr.vsa_aclentp, vsecattr.vsa_aclcnt); 5190174294Sobrien if (vsecattr.vsa_aclentp != NULL) 5191174294Sobrien kmem_free(vsecattr.vsa_aclentp, vsecattr.vsa_aclentsz); 5192174294Sobrien 5193119679Smbr return (error); 5194119679Smbr} 5195119679Smbr 5196119679Smbrint 5197174294Sobrienzfs_freebsd_setacl(ap) 5198174294Sobrien struct vop_setacl_args /* { 5199174294Sobrien struct vnode *vp; 5200174294Sobrien acl_type_t type; 5201174294Sobrien struct acl *aclp; 5202119679Smbr struct ucred *cred; 5203119679Smbr struct thread *td; 5204119679Smbr } */ *ap; 5205119679Smbr{ 5206119679Smbr int error; 5207174294Sobrien vsecattr_t vsecattr; 5208119679Smbr int aclbsize; /* size of acl list in bytes */ 5209174294Sobrien aclent_t *aaclp; 5210119679Smbr 5211174294Sobrien if (ap->a_type != ACL_TYPE_NFS4) 5212174294Sobrien return (EINVAL); 5213119679Smbr 5214119679Smbr if (ap->a_aclp->acl_cnt < 1 || ap->a_aclp->acl_cnt > MAX_ACL_ENTRIES) 5215174294Sobrien return (EINVAL); 5216174294Sobrien 5217174294Sobrien /* 5218174294Sobrien * With NFSv4 ACLs, chmod(2) may need to add additional entries, 5219119679Smbr * splitting every entry into two and appending "canonical six" 5220119679Smbr * entries at the end. Don't allow for setting an ACL that would 5221174294Sobrien * cause chmod(2) to run out of ACL entries. 5222119679Smbr */ 5223174294Sobrien if (ap->a_aclp->acl_cnt * 2 + 6 > ACL_MAX_ENTRIES) 5224174294Sobrien return (ENOSPC); 5225174294Sobrien 5226174294Sobrien error = acl_nfs4_check(ap->a_aclp, ap->a_vp->v_type == VDIR); 5227174294Sobrien if (error != 0) 5228174294Sobrien return (error); 5229174294Sobrien 5230174294Sobrien vsecattr.vsa_mask = VSA_ACE; 5231174294Sobrien aclbsize = ap->a_aclp->acl_cnt * sizeof(ace_t); 5232174294Sobrien vsecattr.vsa_aclentp = kmem_alloc(aclbsize, KM_SLEEP); 5233174294Sobrien aaclp = vsecattr.vsa_aclentp; 5234174294Sobrien vsecattr.vsa_aclentsz = aclbsize; 5235174294Sobrien 5236174294Sobrien aces_from_acl(vsecattr.vsa_aclentp, &vsecattr.vsa_aclcnt, ap->a_aclp); 5237174294Sobrien error = zfs_setsecattr(ap->a_vp, &vsecattr, 0, ap->a_cred, NULL); 5238174294Sobrien kmem_free(aaclp, aclbsize); 5239174294Sobrien 5240174294Sobrien return (error); 5241174294Sobrien} 5242174294Sobrien 5243174294Sobrienint 5244174294Sobrienzfs_freebsd_aclcheck(ap) 5245174294Sobrien struct vop_aclcheck_args /* { 5246174294Sobrien struct vnode *vp; 5247174294Sobrien acl_type_t type; 5248174294Sobrien struct acl *aclp; 5249174294Sobrien struct ucred *cred; 5250174294Sobrien struct thread *td; 5251174294Sobrien } */ *ap; 5252174294Sobrien{ 5253174294Sobrien 5254174294Sobrien return (EOPNOTSUPP); 5255174294Sobrien} 5256174294Sobrien 5257174294Sobrienstruct vop_vector zfs_vnodeops; 5258174294Sobrienstruct vop_vector zfs_fifoops; 5259174294Sobrienstruct vop_vector zfs_shareops; 5260174294Sobrien 5261174294Sobrienstruct vop_vector zfs_vnodeops = { 5262174294Sobrien .vop_default = &default_vnodeops, 5263174294Sobrien .vop_inactive = zfs_freebsd_inactive, 5264174294Sobrien .vop_reclaim = zfs_freebsd_reclaim, 5265174294Sobrien .vop_access = zfs_freebsd_access, 5266174294Sobrien#ifdef FREEBSD_NAMECACHE 5267174294Sobrien .vop_lookup = vfs_cache_lookup, 5268174294Sobrien .vop_cachedlookup = zfs_freebsd_lookup, 5269174294Sobrien#else 5270174294Sobrien .vop_lookup = zfs_freebsd_lookup, 5271174294Sobrien#endif 5272174294Sobrien .vop_getattr = zfs_freebsd_getattr, 5273174294Sobrien .vop_setattr = zfs_freebsd_setattr, 5274174294Sobrien .vop_create = zfs_freebsd_create, 5275174294Sobrien .vop_mknod = zfs_freebsd_create, 5276174294Sobrien .vop_mkdir = zfs_freebsd_mkdir, 5277174294Sobrien .vop_readdir = zfs_freebsd_readdir, 5278174294Sobrien .vop_fsync = zfs_freebsd_fsync, 5279174294Sobrien .vop_open = zfs_freebsd_open, 5280174294Sobrien .vop_close = zfs_freebsd_close, 5281174294Sobrien .vop_rmdir = zfs_freebsd_rmdir, 5282174294Sobrien .vop_ioctl = zfs_freebsd_ioctl, 5283174294Sobrien .vop_link = zfs_freebsd_link, 5284174294Sobrien .vop_symlink = zfs_freebsd_symlink, 5285174294Sobrien .vop_readlink = zfs_freebsd_readlink, 5286174294Sobrien .vop_read = zfs_freebsd_read, 5287174294Sobrien .vop_write = zfs_freebsd_write, 5288174294Sobrien .vop_remove = zfs_freebsd_remove, 5289174294Sobrien .vop_rename = zfs_freebsd_rename, 5290174294Sobrien .vop_pathconf = zfs_freebsd_pathconf, 5291174294Sobrien .vop_bmap = VOP_EOPNOTSUPP, 5292174294Sobrien .vop_fid = zfs_freebsd_fid, 5293174294Sobrien .vop_getextattr = zfs_getextattr, 5294174294Sobrien .vop_deleteextattr = zfs_deleteextattr, 5295174294Sobrien .vop_setextattr = zfs_setextattr, 5296174294Sobrien .vop_listextattr = zfs_listextattr, 5297174294Sobrien .vop_getacl = zfs_freebsd_getacl, 5298174294Sobrien .vop_setacl = zfs_freebsd_setacl, 5299174294Sobrien .vop_aclcheck = zfs_freebsd_aclcheck, 5300174294Sobrien}; 5301174294Sobrien 5302119679Smbrstruct vop_vector zfs_fifoops = { 5303119679Smbr .vop_default = &fifo_specops, 5304119679Smbr .vop_fsync = zfs_freebsd_fsync, 5305119679Smbr .vop_access = zfs_freebsd_access, 5306119679Smbr .vop_getattr = zfs_freebsd_getattr, 5307119679Smbr .vop_inactive = zfs_freebsd_inactive, 5308119679Smbr .vop_read = VOP_PANIC, 5309174294Sobrien .vop_reclaim = zfs_freebsd_reclaim, 5310174294Sobrien .vop_setattr = zfs_freebsd_setattr, 5311174294Sobrien .vop_write = VOP_PANIC, 5312119679Smbr .vop_pathconf = zfs_freebsd_fifo_pathconf, 5313119679Smbr .vop_fid = zfs_freebsd_fid, 5314119679Smbr .vop_getacl = zfs_freebsd_getacl, 5315119679Smbr .vop_setacl = zfs_freebsd_setacl, 5316119679Smbr .vop_aclcheck = zfs_freebsd_aclcheck, 5317119679Smbr}; 5318119679Smbr 5319119679Smbr/* 5320119679Smbr * special share hidden files vnode operations template 5321119679Smbr */ 5322119679Smbrstruct vop_vector zfs_shareops = { 5323119679Smbr .vop_default = &default_vnodeops, 5324174294Sobrien .vop_access = zfs_freebsd_access, 5325119679Smbr .vop_inactive = zfs_freebsd_inactive, 5326119679Smbr .vop_reclaim = zfs_freebsd_reclaim, 5327119679Smbr .vop_fid = zfs_freebsd_fid, 5328119679Smbr .vop_pathconf = zfs_freebsd_pathconf, 5329174294Sobrien}; 5330119679Smbr