X-Git-Url: https://git.camperquake.de/gitweb.cgi?a=blobdiff_plain;f=module%2Fzfs%2Fzfs_vnops.c;h=b666ee39ccbe78732d929240b70f61875713f044;hb=a405c8a665bf7d96880c97bcb783cf84d04e3e76;hp=aa43c065f083d4a8f684c7bb9afe4c4f637eff02;hpb=428870ff734fdaccc342b33fc53cf94724409a46;p=zfs.git diff --git a/module/zfs/zfs_vnops.c b/module/zfs/zfs_vnops.c index aa43c06..b666ee3 100644 --- a/module/zfs/zfs_vnops.c +++ b/module/zfs/zfs_vnops.c @@ -25,6 +25,8 @@ /* Portions Copyright 2007 Jeremy Teo */ /* Portions Copyright 2010 Robert Milkowski */ +#ifdef HAVE_ZPL + #include #include #include @@ -72,6 +74,7 @@ #include #include #include +#include #include #include #include @@ -132,7 +135,7 @@ * (6) At the end of each vnode op, the DMU tx must always commit, * regardless of whether there were any errors. * - * (7) After dropping all locks, invoke zil_commit(zilog, seq, foid) + * (7) After dropping all locks, invoke zil_commit(zilog, foid) * to ensure that synchronous semantics are provided when necessary. * * In general, this is how things should be ordered in each vnode op: @@ -164,7 +167,7 @@ * rw_exit(...); // drop locks * zfs_dirent_unlock(dl); // unlock directory entry * VN_RELE(...); // release held vnodes - * zil_commit(zilog, seq, foid); // synchronous when necessary + * zil_commit(zilog, foid); // synchronous when necessary * ZFS_EXIT(zfsvfs); // finished in zfs * return (error); // done, report error */ @@ -319,6 +322,7 @@ zfs_ioctl(vnode_t *vp, int com, intptr_t data, int flag, cred_t *cred, return (ENOTTY); } +#if defined(_KERNEL) && defined(HAVE_UIO_RW) /* * Utility functions to map and unmap a single physical page. These * are used to manage the mappable copies of ZFS file data, and therefore @@ -343,6 +347,7 @@ zfs_unmap_page(page_t *pp, caddr_t addr) ppmapout(addr); } } +#endif /* _KERNEL && HAVE_UIO_RW */ /* * When a file is memory mapped, we must keep the IO data synchronized @@ -439,14 +444,14 @@ offset_t zfs_read_chunk_size = 1024 * 1024; /* Tunable */ * vp - atime updated if byte count > 0 */ /* ARGSUSED */ -static int +int zfs_read(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cr, caller_context_t *ct) { znode_t *zp = VTOZ(vp); zfsvfs_t *zfsvfs = zp->z_zfsvfs; objset_t *os; ssize_t n, nbytes; - int error; + int error = 0; rl_t *rl; xuio_t *xuio = NULL; @@ -490,7 +495,7 @@ zfs_read(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cr, caller_context_t *ct) * If we're in FRSYNC mode, sync out this znode before reading it. */ if (ioflag & FRSYNC || zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS) - zil_commit(zfsvfs->z_log, zp->z_last_itx, zp->z_id); + zil_commit(zfsvfs->z_log, zp->z_id); /* * Lock the range against changes. @@ -562,6 +567,7 @@ out: ZFS_EXIT(zfsvfs); return (error); } +EXPORT_SYMBOL(zfs_read); /* * Write the bytes to a file. @@ -583,7 +589,7 @@ out: */ /* ARGSUSED */ -static int +int zfs_write(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cr, caller_context_t *ct) { znode_t *zp = VTOZ(vp); @@ -670,7 +676,7 @@ zfs_write(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cr, caller_context_t *ct) (((xuio_t *)uio)->xu_type == UIOTYPE_ZEROCOPY)) xuio = (xuio_t *)uio; else - uio_prefaultpages(n, uio); + uio_prefaultpages(MIN(n, max_blksz), uio); /* * If in append mode, set the io offset pointer to eof. @@ -759,8 +765,8 @@ again: max_blksz); ASSERT(abuf != NULL); ASSERT(arc_buf_size(abuf) == max_blksz); - if (error = uiocopy(abuf->b_data, max_blksz, - UIO_WRITE, uio, &cbytes)) { + if ((error = uiocopy(abuf->b_data, max_blksz, + UIO_WRITE, uio, &cbytes))) { dmu_return_arcbuf(abuf); break; } @@ -866,6 +872,8 @@ again: * been done, but that would still expose the ISUID/ISGID * to another app after the partial write is committed. * + * Note: we don't call zfs_fuid_map_id() here because + * user 0 is not an ephemeral uid. */ mutex_enter(&zp->z_acl_lock); if ((zp->z_mode & (S_IXUSR | (S_IXUSR >> 3) | @@ -893,6 +901,14 @@ again: uio->uio_loffset); ASSERT(error == 0); } + /* + * If we are replaying and eof is non zero then force + * the file size to the specified eof. Note, there's no + * concurrency during replay. + */ + if (zfsvfs->z_replay && zfsvfs->z_replay_eof != 0) + zp->z_size = zfsvfs->z_replay_eof; + error = sa_bulk_update(zp->z_sa_hdl, bulk, count, tx); zfs_log_write(zilog, tx, TX_WRITE, zp, woff, tx_bytes, ioflag); @@ -902,6 +918,9 @@ again: break; ASSERT(tx_bytes == nbytes); n -= nbytes; + + if (!xuio && n > 0) + uio_prefaultpages(MIN(n, max_blksz), uio); } zfs_range_unlock(rl); @@ -917,11 +936,12 @@ again: if (ioflag & (FSYNC | FDSYNC) || zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS) - zil_commit(zilog, zp->z_last_itx, zp->z_id); + zil_commit(zilog, zp->z_id); ZFS_EXIT(zfsvfs); return (0); } +EXPORT_SYMBOL(zfs_write); void zfs_get_done(zgd_t *zgd, int error) @@ -1135,7 +1155,7 @@ specvp_check(vnode_t **vpp, cred_t *cr) * NA */ /* ARGSUSED */ -static int +int zfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp, int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct, int *direntflags, pathname_t *realpnp) @@ -1206,7 +1226,7 @@ zfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp, return (EINVAL); } - if (error = zfs_get_xattrdir(VTOZ(dvp), vpp, cr, flags)) { + if ((error = zfs_get_xattrdir(VTOZ(dvp), vpp, cr, flags))) { ZFS_EXIT(zfsvfs); return (error); } @@ -1215,8 +1235,8 @@ zfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp, * Do we have permission to get into attribute directory? */ - if (error = zfs_zaccess(VTOZ(*vpp), ACE_EXECUTE, 0, - B_FALSE, cr)) { + if ((error = zfs_zaccess(VTOZ(*vpp), ACE_EXECUTE, 0, + B_FALSE, cr))) { VN_RELE(*vpp); *vpp = NULL; } @@ -1234,7 +1254,7 @@ zfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp, * Check accessibility of directory. */ - if (error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr)) { + if ((error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr))) { ZFS_EXIT(zfsvfs); return (error); } @@ -1252,6 +1272,7 @@ zfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp, ZFS_EXIT(zfsvfs); return (error); } +EXPORT_SYMBOL(zfs_lookup); /* * Attempt to create a new entry in a directory. If the entry @@ -1279,8 +1300,8 @@ zfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp, */ /* ARGSUSED */ -static int -zfs_create(vnode_t *dvp, char *name, vattr_t *vap, vcexcl_t excl, +int +zfs_create(vnode_t *dvp, char *name, vattr_t *vap, int excl, int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct, vsecattr_t *vsecp) { @@ -1293,7 +1314,7 @@ zfs_create(vnode_t *dvp, char *name, vattr_t *vap, vcexcl_t excl, int error; ksid_t *ksid; uid_t uid; - gid_t gid = crgetgid(cr); + gid_t gid; zfs_acl_ids_t acl_ids; boolean_t fuid_dirtied; boolean_t have_acl = B_FALSE; @@ -1303,6 +1324,7 @@ zfs_create(vnode_t *dvp, char *name, vattr_t *vap, vcexcl_t excl, * make sure file system is at proper version */ + gid = crgetgid(cr); ksid = crgetsid(cr, KSID_OWNER); if (ksid) uid = ksid_getid(ksid); @@ -1356,6 +1378,8 @@ top: error = zfs_dirent_lock(&dl, dzp, name, &zp, zflg, NULL, NULL); if (error) { + if (have_acl) + zfs_acl_ids_free(&acl_ids); if (strcmp(name, "..") == 0) error = EISDIR; ZFS_EXIT(zfsvfs); @@ -1370,7 +1394,9 @@ top: * Create a new file object and update the directory * to reference it. */ - if (error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr)) { + if ((error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr))) { + if (have_acl) + zfs_acl_ids_free(&acl_ids); goto out; } @@ -1381,6 +1407,8 @@ top: if ((dzp->z_pflags & ZFS_XATTR) && (vap->va_type != VREG)) { + if (have_acl) + zfs_acl_ids_free(&acl_ids); error = EINVAL; goto out; } @@ -1440,6 +1468,10 @@ top: } else { int aflags = (flag & FAPPEND) ? V_APPEND : 0; + if (have_acl) + zfs_acl_ids_free(&acl_ids); + have_acl = B_FALSE; + /* * A directory entry already exists for this name. */ @@ -1496,11 +1528,12 @@ out: } if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS) - zil_commit(zilog, UINT64_MAX, 0); + zil_commit(zilog, 0); ZFS_EXIT(zfsvfs); return (error); } +EXPORT_SYMBOL(zfs_create); /* * Remove an entry from a directory. @@ -1522,17 +1555,18 @@ out: uint64_t null_xattr = 0; /*ARGSUSED*/ -static int +int zfs_remove(vnode_t *dvp, char *name, cred_t *cr, caller_context_t *ct, int flags) { znode_t *zp, *dzp = VTOZ(dvp); - znode_t *xzp = NULL; + znode_t *xzp; vnode_t *vp; zfsvfs_t *zfsvfs = dzp->z_zfsvfs; zilog_t *zilog; - uint64_t acl_obj, xattr_obj = 0; + uint64_t acl_obj, xattr_obj; uint64_t xattr_obj_unlinked = 0; + uint64_t obj = 0; zfs_dirlock_t *dl; dmu_tx_t *tx; boolean_t may_delete_now, delete_now = FALSE; @@ -1554,11 +1588,13 @@ zfs_remove(vnode_t *dvp, char *name, cred_t *cr, caller_context_t *ct, } top: + xattr_obj = 0; + xzp = NULL; /* * Attempt to lock directory; fail if entry doesn't exist. */ - if (error = zfs_dirent_lock(&dl, dzp, name, &zp, zflg, - NULL, realnmp)) { + if ((error = zfs_dirent_lock(&dl, dzp, name, &zp, zflg, + NULL, realnmp))) { if (realnmp) pn_free(realnmp); ZFS_EXIT(zfsvfs); @@ -1567,7 +1603,7 @@ top: vp = ZTOV(zp); - if (error = zfs_zaccess_delete(dzp, zp, cr)) { + if ((error = zfs_zaccess_delete(dzp, zp, cr))) { goto out; } @@ -1587,7 +1623,7 @@ top: dnlc_remove(dvp, name); mutex_enter(&vp->v_lock); - may_delete_now = vp->v_count == 1 && !vn_has_cached_data(vp); + may_delete_now = ((vp->v_count == 1) && (!vn_has_cached_data(vp))); mutex_exit(&vp->v_lock); /* @@ -1596,6 +1632,7 @@ top: * other holds on the vnode. So we dmu_tx_hold() the right things to * allow for either case. */ + obj = zp->z_id; tx = dmu_tx_create(zfsvfs->z_os); dmu_tx_hold_zap(tx, dzp->z_id, FALSE, name); dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE); @@ -1612,16 +1649,17 @@ top: /* are there any extended attributes? */ error = sa_lookup(zp->z_sa_hdl, SA_ZPL_XATTR(zfsvfs), &xattr_obj, sizeof (xattr_obj)); - if (xattr_obj) { + if (error == 0 && xattr_obj) { error = zfs_zget(zfsvfs, xattr_obj, &xzp); ASSERT3U(error, ==, 0); dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE); dmu_tx_hold_sa(tx, xzp->z_sa_hdl, B_FALSE); } - /* are there any additional acls */ - if ((acl_obj = ZFS_EXTERNAL_ACL(zp)) != 0 && may_delete_now) + mutex_enter(&zp->z_lock); + if ((acl_obj = zfs_external_acl(zp)) != 0 && may_delete_now) dmu_tx_hold_free(tx, acl_obj, 0, DMU_OBJECT_END); + mutex_exit(&zp->z_lock); /* charge as an update -- would be nice not to charge at all */ dmu_tx_hold_zap(tx, zfsvfs->z_unlinkedobj, FALSE, NULL); @@ -1630,6 +1668,8 @@ top: if (error) { zfs_dirent_unlock(dl); VN_RELE(vp); + if (xzp) + VN_RELE(ZTOV(xzp)); if (error == ERESTART) { dmu_tx_wait(tx); dmu_tx_abort(tx); @@ -1654,13 +1694,18 @@ top: if (unlinked) { + /* + * Hold z_lock so that we can make sure that the ACL obj + * hasn't changed. Could have been deleted due to + * zfs_sa_upgrade(). + */ + mutex_enter(&zp->z_lock); mutex_enter(&vp->v_lock); - (void) sa_lookup(zp->z_sa_hdl, SA_ZPL_XATTR(zfsvfs), &xattr_obj_unlinked, sizeof (xattr_obj_unlinked)); delete_now = may_delete_now && !toobig && vp->v_count == 1 && !vn_has_cached_data(vp) && - xattr_obj == xattr_obj_unlinked && ZFS_EXTERNAL_ACL(zp) == + xattr_obj == xattr_obj_unlinked && zfs_external_acl(zp) == acl_obj; mutex_exit(&vp->v_lock); } @@ -1676,6 +1721,7 @@ top: ASSERT3U(error, ==, 0); mutex_exit(&xzp->z_lock); zfs_unlinked_add(xzp, tx); + if (zp->z_is_sa) error = sa_remove(zp->z_sa_hdl, SA_ZPL_XATTR(zfsvfs), tx); @@ -1685,7 +1731,6 @@ top: sizeof (uint64_t), tx); ASSERT3U(error, ==, 0); } - mutex_enter(&zp->z_lock); mutex_enter(&vp->v_lock); vp->v_count--; ASSERT3U(vp->v_count, ==, 0); @@ -1693,13 +1738,14 @@ top: mutex_exit(&zp->z_lock); zfs_znode_delete(zp, tx); } else if (unlinked) { + mutex_exit(&zp->z_lock); zfs_unlinked_add(zp, tx); } txtype = TX_REMOVE; if (flags & FIGNORECASE) txtype |= TX_CI; - zfs_log_remove(zilog, tx, txtype, dzp, name); + zfs_log_remove(zilog, tx, txtype, dzp, name, obj); dmu_tx_commit(tx); out: @@ -1714,11 +1760,12 @@ out: VN_RELE(ZTOV(xzp)); if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS) - zil_commit(zilog, UINT64_MAX, 0); + zil_commit(zilog, 0); ZFS_EXIT(zfsvfs); return (error); } +EXPORT_SYMBOL(zfs_remove); /* * Create a new directory and insert it into dvp using the name @@ -1741,7 +1788,7 @@ out: * vp - ctime|mtime|atime updated */ /*ARGSUSED*/ -static int +int zfs_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp, cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp) { @@ -1816,14 +1863,14 @@ zfs_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp, cred_t *cr, top: *vpp = NULL; - if (error = zfs_dirent_lock(&dl, dzp, dirname, &zp, zf, - NULL, NULL)) { + if ((error = zfs_dirent_lock(&dl, dzp, dirname, &zp, zf, + NULL, NULL))) { zfs_acl_ids_free(&acl_ids); ZFS_EXIT(zfsvfs); return (error); } - if (error = zfs_zaccess(dzp, ACE_ADD_SUBDIRECTORY, 0, B_FALSE, cr)) { + if ((error = zfs_zaccess(dzp, ACE_ADD_SUBDIRECTORY, 0, B_FALSE, cr))) { zfs_acl_ids_free(&acl_ids); zfs_dirent_unlock(dl); ZFS_EXIT(zfsvfs); @@ -1896,11 +1943,12 @@ top: zfs_dirent_unlock(dl); if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS) - zil_commit(zilog, UINT64_MAX, 0); + zil_commit(zilog, 0); ZFS_EXIT(zfsvfs); return (0); } +EXPORT_SYMBOL(zfs_mkdir); /* * Remove a directory subdir entry. If the current working @@ -1921,7 +1969,7 @@ top: * dvp - ctime|mtime updated */ /*ARGSUSED*/ -static int +int zfs_rmdir(vnode_t *dvp, char *name, vnode_t *cwd, cred_t *cr, caller_context_t *ct, int flags) { @@ -1947,15 +1995,15 @@ top: /* * Attempt to lock directory; fail if entry doesn't exist. */ - if (error = zfs_dirent_lock(&dl, dzp, name, &zp, zflg, - NULL, NULL)) { + if ((error = zfs_dirent_lock(&dl, dzp, name, &zp, zflg, + NULL, NULL))) { ZFS_EXIT(zfsvfs); return (error); } vp = ZTOV(zp); - if (error = zfs_zaccess_delete(dzp, zp, cr)) { + if ((error = zfs_zaccess_delete(dzp, zp, cr))) { goto out; } @@ -2011,7 +2059,7 @@ top: uint64_t txtype = TX_RMDIR; if (flags & FIGNORECASE) txtype |= TX_CI; - zfs_log_remove(zilog, tx, txtype, dzp, name); + zfs_log_remove(zilog, tx, txtype, dzp, name, ZFS_NO_OBJECT); } dmu_tx_commit(tx); @@ -2024,11 +2072,12 @@ out: VN_RELE(vp); if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS) - zil_commit(zilog, UINT64_MAX, 0); + zil_commit(zilog, 0); ZFS_EXIT(zfsvfs); return (error); } +EXPORT_SYMBOL(zfs_rmdir); /* * Read as many directory entries as will fit into the provided @@ -2164,7 +2213,7 @@ zfs_readdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp, while (outcount < bytes_wanted) { ino64_t objnum; ushort_t reclen; - off64_t *next; + off64_t *next = NULL; /* * Special case `.', `..', and `.zfs'. @@ -2290,7 +2339,8 @@ zfs_readdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp, } else { offset += 1; } - *next = offset; + if (next) + *next = offset; } zp->z_zn_prefetch = B_FALSE; /* a lookup will re-enable pre-fetching */ @@ -2322,7 +2372,7 @@ update: ulong_t zfs_fsync_sync_cnt = 4; -static int +int zfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct) { znode_t *zp = VTOZ(vp); @@ -2343,11 +2393,12 @@ zfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct) if (zfsvfs->z_os->os_sync != ZFS_SYNC_DISABLED) { ZFS_ENTER(zfsvfs); ZFS_VERIFY_ZP(zp); - zil_commit(zfsvfs->z_log, zp->z_last_itx, zp->z_id); + zil_commit(zfsvfs->z_log, zp->z_id); ZFS_EXIT(zfsvfs); } return (0); } +EXPORT_SYMBOL(zfs_fsync); /* @@ -2366,7 +2417,7 @@ zfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct) * RETURN: 0 (always succeeds) */ /* ARGSUSED */ -static int +int zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, caller_context_t *ct) { @@ -2384,6 +2435,8 @@ zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, ZFS_ENTER(zfsvfs); ZFS_VERIFY_ZP(zp); + zfs_fuid_map_ids(zp, cr, &vap->va_uid, &vap->va_gid); + SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MTIME(zfsvfs), NULL, &mtime, 16); SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), NULL, &ctime, 16); @@ -2397,9 +2450,10 @@ zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, * Also, if we are the owner don't bother, since owner should * always be allowed to read basic attributes of file. */ - if (!(zp->z_pflags & ZFS_ACL_TRIVIAL) && (zp->z_uid != crgetuid(cr))) { - if (error = zfs_zaccess(zp, ACE_READ_ATTRIBUTES, 0, - skipaclchk, cr)) { + if (!(zp->z_pflags & ZFS_ACL_TRIVIAL) && + (vap->va_uid != crgetuid(cr))) { + if ((error = zfs_zaccess(zp, ACE_READ_ATTRIBUTES, 0, + skipaclchk, cr))) { ZFS_EXIT(zfsvfs); return (error); } @@ -2413,8 +2467,6 @@ zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, mutex_enter(&zp->z_lock); vap->va_type = vp->v_type; vap->va_mode = zp->z_mode & MODEMASK; - vap->va_uid = zp->z_uid; - vap->va_gid = zp->z_gid; vap->va_fsid = zp->z_zfsvfs->z_vfs->vfs_dev; vap->va_nodeid = zp->z_id; if ((vp->v_flag & VROOT) && zfs_show_ctldir(zp)) @@ -2515,6 +2567,22 @@ zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, xoap->xoa_reparse = ((zp->z_pflags & ZFS_REPARSE) != 0); XVA_SET_RTN(xvap, XAT_REPARSE); } + if (XVA_ISSET_REQ(xvap, XAT_GEN)) { + xoap->xoa_generation = zp->z_gen; + XVA_SET_RTN(xvap, XAT_GEN); + } + + if (XVA_ISSET_REQ(xvap, XAT_OFFLINE)) { + xoap->xoa_offline = + ((zp->z_pflags & ZFS_OFFLINE) != 0); + XVA_SET_RTN(xvap, XAT_OFFLINE); + } + + if (XVA_ISSET_REQ(xvap, XAT_SPARSE)) { + xoap->xoa_sparse = + ((zp->z_pflags & ZFS_SPARSE) != 0); + XVA_SET_RTN(xvap, XAT_SPARSE); + } } ZFS_TIME_DECODE(&vap->va_atime, zp->z_atime); @@ -2535,6 +2603,7 @@ zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, ZFS_EXIT(zfsvfs); return (0); } +EXPORT_SYMBOL(zfs_getattr); /* * Set the file attributes to the values contained in the @@ -2555,7 +2624,7 @@ zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, * vp - ctime updated, mtime updated if size changed. */ /* ARGSUSED */ -static int +int zfs_setattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, caller_context_t *ct) { @@ -2570,7 +2639,7 @@ zfs_setattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, int trim_mask = 0; uint64_t new_mode; uint64_t new_uid, new_gid; - uint64_t xattr_obj = 0; + uint64_t xattr_obj; uint64_t mtime[2], ctime[2]; znode_t *attrzp; int need_policy = FALSE; @@ -2578,7 +2647,7 @@ zfs_setattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, zfs_fuid_info_t *fuidp = NULL; xvattr_t *xvap = (xvattr_t *)vap; /* vap may be an xvattr_t * */ xoptattr_t *xoap; - zfs_acl_t *aclp = NULL; + zfs_acl_t *aclp; boolean_t skipaclchk = (flags & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE; boolean_t fuid_dirtied = B_FALSE; sa_bulk_attr_t bulk[7], xattr_bulk[7]; @@ -2657,6 +2726,7 @@ zfs_setattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, top: attrzp = NULL; + aclp = NULL; /* Can this be moved to before the top label? */ if (zfsvfs->z_vfs->vfs_flag & VFS_RDONLY) { @@ -2692,6 +2762,8 @@ top: ((mask & AT_XVATTR) && (XVA_ISSET_REQ(xvap, XAT_HIDDEN) || XVA_ISSET_REQ(xvap, XAT_READONLY) || XVA_ISSET_REQ(xvap, XAT_ARCHIVE) || + XVA_ISSET_REQ(xvap, XAT_OFFLINE) || + XVA_ISSET_REQ(xvap, XAT_SPARSE) || XVA_ISSET_REQ(xvap, XAT_CREATETIME) || XVA_ISSET_REQ(xvap, XAT_SYSTEM)))) { need_policy = zfs_zaccess(zp, ACE_WRITE_ATTRIBUTES, 0, @@ -2748,8 +2820,7 @@ top: mutex_enter(&zp->z_lock); oldva.va_mode = zp->z_mode; - oldva.va_uid = zp->z_uid; - oldva.va_gid = zp->z_gid; + zfs_fuid_map_ids(zp, cr, &oldva.va_uid, &oldva.va_gid); if (mask & AT_XVATTR) { /* * Update xvattr mask to include only those attributes @@ -2880,10 +2951,10 @@ top: mask = vap->va_mask; if ((mask & (AT_UID | AT_GID))) { - (void) sa_lookup(zp->z_sa_hdl, SA_ZPL_XATTR(zfsvfs), &xattr_obj, - sizeof (xattr_obj)); + err = sa_lookup(zp->z_sa_hdl, SA_ZPL_XATTR(zfsvfs), + &xattr_obj, sizeof (xattr_obj)); - if (xattr_obj) { + if (err == 0 && xattr_obj) { err = zfs_zget(zp->z_zfsvfs, xattr_obj, &attrzp); if (err) goto out2; @@ -2891,8 +2962,10 @@ top: if (mask & AT_UID) { new_uid = zfs_fuid_create(zfsvfs, (uint64_t)vap->va_uid, cr, ZFS_OWNER, &fuidp); - if (vap->va_uid != zp->z_uid && + if (new_uid != zp->z_uid && zfs_fuid_overquota(zfsvfs, B_FALSE, new_uid)) { + if (attrzp) + VN_RELE(ZTOV(attrzp)); err = EDQUOT; goto out2; } @@ -2903,6 +2976,8 @@ top: cr, ZFS_GROUP, &fuidp); if (new_gid != zp->z_gid && zfs_fuid_overquota(zfsvfs, B_TRUE, new_gid)) { + if (attrzp) + VN_RELE(ZTOV(attrzp)); err = EDQUOT; goto out2; } @@ -2912,32 +2987,33 @@ top: if (mask & AT_MODE) { uint64_t pmode = zp->z_mode; + uint64_t acl_obj; new_mode = (pmode & S_IFMT) | (vap->va_mode & ~S_IFMT); - if (err = zfs_acl_chmod_setattr(zp, &aclp, new_mode)) - goto out; + zfs_acl_chmod_setattr(zp, &aclp, new_mode); - if (!zp->z_is_sa && ZFS_EXTERNAL_ACL(zp)) { + mutex_enter(&zp->z_lock); + if (!zp->z_is_sa && ((acl_obj = zfs_external_acl(zp)) != 0)) { /* * Are we upgrading ACL from old V0 format * to V1 format? */ - if (zfsvfs->z_version <= ZPL_VERSION_FUID && - ZNODE_ACL_VERSION(zp) == + if (zfsvfs->z_version >= ZPL_VERSION_FUID && + zfs_znode_acl_version(zp) == ZFS_ACL_VERSION_INITIAL) { - dmu_tx_hold_free(tx, - ZFS_EXTERNAL_ACL(zp), 0, + dmu_tx_hold_free(tx, acl_obj, 0, DMU_OBJECT_END); dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, aclp->z_acl_bytes); } else { - dmu_tx_hold_write(tx, ZFS_EXTERNAL_ACL(zp), 0, + dmu_tx_hold_write(tx, acl_obj, 0, aclp->z_acl_bytes); } } else if (!zp->z_is_sa && aclp->z_acl_bytes > ZFS_ACE_SPACE) { dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, aclp->z_acl_bytes); } + mutex_exit(&zp->z_lock); dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE); } else { if ((mask & AT_XVATTR) && @@ -2973,12 +3049,17 @@ top: * updated as a side-effect of calling this function. */ + + if (mask & (AT_UID|AT_GID|AT_MODE)) + mutex_enter(&zp->z_acl_lock); mutex_enter(&zp->z_lock); SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zfsvfs), NULL, &zp->z_pflags, sizeof (zp->z_pflags)); if (attrzp) { + if (mask & (AT_UID|AT_GID|AT_MODE)) + mutex_enter(&attrzp->z_acl_lock); mutex_enter(&attrzp->z_lock); SA_ADD_BULK_ATTR(xattr_bulk, xattr_count, SA_ZPL_FLAGS(zfsvfs), NULL, &attrzp->z_pflags, @@ -2990,26 +3071,24 @@ top: if (mask & AT_UID) { SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_UID(zfsvfs), NULL, &new_uid, sizeof (new_uid)); - zp->z_uid = zfs_fuid_map_id(zfsvfs, new_uid, - cr, ZFS_OWNER); + zp->z_uid = new_uid; if (attrzp) { SA_ADD_BULK_ATTR(xattr_bulk, xattr_count, SA_ZPL_UID(zfsvfs), NULL, &new_uid, sizeof (new_uid)); - attrzp->z_uid = zp->z_uid; + attrzp->z_uid = new_uid; } } if (mask & AT_GID) { SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_GID(zfsvfs), NULL, &new_gid, sizeof (new_gid)); - zp->z_gid = zfs_fuid_map_id(zfsvfs, new_gid, cr, - ZFS_GROUP); + zp->z_gid = new_gid; if (attrzp) { SA_ADD_BULK_ATTR(xattr_bulk, xattr_count, SA_ZPL_GID(zfsvfs), NULL, &new_gid, sizeof (new_gid)); - attrzp->z_gid = zp->z_gid; + attrzp->z_gid = new_gid; } } if (!(mask & AT_MODE)) { @@ -3026,20 +3105,18 @@ top: } if (mask & AT_MODE) { - mutex_enter(&zp->z_acl_lock); SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MODE(zfsvfs), NULL, &new_mode, sizeof (new_mode)); zp->z_mode = new_mode; ASSERT3U((uintptr_t)aclp, !=, NULL); err = zfs_aclset_common(zp, aclp, cr, tx); ASSERT3U(err, ==, 0); + if (zp->z_acl_cached) + zfs_acl_free(zp->z_acl_cached); zp->z_acl_cached = aclp; aclp = NULL; - mutex_exit(&zp->z_acl_lock); } - if (attrzp) - mutex_exit(&attrzp->z_lock); if (mask & AT_ATIME) { ZFS_TIME_ENCODE(&vap->va_atime, zp->z_atime); @@ -3118,7 +3195,14 @@ top: zfs_log_setattr(zilog, tx, TX_SETATTR, zp, vap, mask, fuidp); mutex_exit(&zp->z_lock); + if (mask & (AT_UID|AT_GID|AT_MODE)) + mutex_exit(&zp->z_acl_lock); + if (attrzp) { + if (mask & (AT_UID|AT_GID|AT_MODE)) + mutex_exit(&attrzp->z_acl_lock); + mutex_exit(&attrzp->z_lock); + } out: if (err == 0 && attrzp) { err2 = sa_bulk_update(attrzp->z_sa_hdl, xattr_bulk, @@ -3145,14 +3229,14 @@ out: dmu_tx_commit(tx); } - out2: if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS) - zil_commit(zilog, UINT64_MAX, 0); + zil_commit(zilog, 0); ZFS_EXIT(zfsvfs); return (err); } +EXPORT_SYMBOL(zfs_setattr); typedef struct zfs_zlock { krwlock_t *zl_rwlock; /* lock we acquired */ @@ -3270,7 +3354,7 @@ zfs_rename_lock(znode_t *szp, znode_t *tdzp, znode_t *sdzp, zfs_zlock_t **zlpp) * sdvp,tdvp - ctime|mtime updated */ /*ARGSUSED*/ -static int +int zfs_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr, caller_context_t *ct, int flags) { @@ -3448,7 +3532,7 @@ top: * done in a single check. */ - if (error = zfs_zaccess_rename(sdzp, szp, tdzp, tzp, cr)) + if ((error = zfs_zaccess_rename(sdzp, szp, tdzp, tzp, cr))) goto out; if (ZTOV(szp)->v_type == VDIR) { @@ -3456,7 +3540,7 @@ top: * Check to make sure rename is valid. * Can't do a move like this: /usr/a/b to /usr/a/b/c/d */ - if (error = zfs_rename_lock(szp, tdzp, sdzp, &zl)) + if ((error = zfs_rename_lock(szp, tdzp, sdzp, &zl))) goto out; } @@ -3555,9 +3639,8 @@ top: error = zfs_link_destroy(sdl, szp, tx, ZRENAMING, NULL); if (error == 0) { zfs_log_rename(zilog, tx, TX_RENAME | - (flags & FIGNORECASE ? TX_CI : 0), - sdzp, sdl->dl_name, tdzp, tdl->dl_name, - szp); + (flags & FIGNORECASE ? TX_CI : 0), sdzp, + sdl->dl_name, tdzp, tdl->dl_name, szp); /* * Update path information for the target vnode @@ -3600,11 +3683,12 @@ out: VN_RELE(ZTOV(tzp)); if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS) - zil_commit(zilog, UINT64_MAX, 0); + zil_commit(zilog, 0); ZFS_EXIT(zfsvfs); return (error); } +EXPORT_SYMBOL(zfs_rename); /* * Insert the indicated symbolic reference entry into the directory. @@ -3624,7 +3708,7 @@ out: * dvp - ctime|mtime updated */ /*ARGSUSED*/ -static int +int zfs_symlink(vnode_t *dvp, char *name, vattr_t *vap, char *link, cred_t *cr, caller_context_t *ct, int flags) { @@ -3675,7 +3759,7 @@ top: return (error); } - if (error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr)) { + if ((error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr))) { zfs_acl_ids_free(&acl_ids); zfs_dirent_unlock(dl); ZFS_EXIT(zfsvfs); @@ -3724,11 +3808,13 @@ top: if (fuid_dirtied) zfs_fuid_sync(zfsvfs, tx); + mutex_enter(&zp->z_lock); if (zp->z_is_sa) error = sa_update(zp->z_sa_hdl, SA_ZPL_SYMLINK(zfsvfs), link, len, tx); else zfs_sa_symlink(zp, link, len, tx); + mutex_exit(&zp->z_lock); zp->z_size = len; (void) sa_update(zp->z_sa_hdl, SA_ZPL_SIZE(zfsvfs), @@ -3751,11 +3837,12 @@ top: VN_RELE(ZTOV(zp)); if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS) - zil_commit(zilog, UINT64_MAX, 0); + zil_commit(zilog, 0); ZFS_EXIT(zfsvfs); return (error); } +EXPORT_SYMBOL(zfs_symlink); /* * Return, in the buffer contained in the provided uio structure, @@ -3775,7 +3862,7 @@ top: * vp - atime updated */ /* ARGSUSED */ -static int +int zfs_readlink(vnode_t *vp, uio_t *uio, cred_t *cr, caller_context_t *ct) { znode_t *zp = VTOZ(vp); @@ -3785,17 +3872,20 @@ zfs_readlink(vnode_t *vp, uio_t *uio, cred_t *cr, caller_context_t *ct) ZFS_ENTER(zfsvfs); ZFS_VERIFY_ZP(zp); + mutex_enter(&zp->z_lock); if (zp->z_is_sa) error = sa_lookup_uio(zp->z_sa_hdl, SA_ZPL_SYMLINK(zfsvfs), uio); else error = zfs_sa_readlink(zp, uio); + mutex_exit(&zp->z_lock); ZFS_ACCESSTIME_STAMP(zfsvfs, zp); ZFS_EXIT(zfsvfs); return (error); } +EXPORT_SYMBOL(zfs_readlink); /* * Insert a new entry into directory tdvp referencing svp. @@ -3814,7 +3904,7 @@ zfs_readlink(vnode_t *vp, uio_t *uio, cred_t *cr, caller_context_t *ct) * svp - ctime updated */ /* ARGSUSED */ -static int +int zfs_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr, caller_context_t *ct, int flags) { @@ -3828,6 +3918,7 @@ zfs_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr, int error; int zf = ZNEW; uint64_t parent; + uid_t owner; ASSERT(tdvp->v_type == VDIR); @@ -3887,13 +3978,13 @@ zfs_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr, } - if (szp->z_uid != crgetuid(cr) && - secpolicy_basic_link(cr) != 0) { + owner = zfs_fuid_map_id(zfsvfs, szp->z_uid, cr, ZFS_OWNER); + if (owner != crgetuid(cr) && secpolicy_basic_link(cr) != 0) { ZFS_EXIT(zfsvfs); return (EPERM); } - if (error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr)) { + if ((error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr))) { ZFS_EXIT(zfsvfs); return (error); } @@ -3944,11 +4035,12 @@ top: } if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS) - zil_commit(zilog, UINT64_MAX, 0); + zil_commit(zilog, 0); ZFS_EXIT(zfsvfs); return (error); } +EXPORT_SYMBOL(zfs_link); /* * zfs_null_putapage() is used when the file system has been force @@ -4181,7 +4273,7 @@ zfs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr, out: zfs_range_unlock(rl); if ((flags & B_ASYNC) == 0 || zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS) - zil_commit(zfsvfs->z_log, UINT64_MAX, zp->z_id); + zil_commit(zfsvfs->z_log, zp->z_id); ZFS_EXIT(zfsvfs); return (error); } @@ -4246,6 +4338,7 @@ zfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct) zfs_zinactive(zp); rw_exit(&zfsvfs->z_teardown_inactive_lock); } +EXPORT_SYMBOL(zfs_inactive); /* * Bounds-check the seek operation. @@ -4634,7 +4727,7 @@ zfs_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr, * vp - ctime|mtime updated */ /* ARGSUSED */ -static int +int zfs_space(vnode_t *vp, int cmd, flock64_t *bfp, int flag, offset_t offset, cred_t *cr, caller_context_t *ct) { @@ -4651,7 +4744,7 @@ zfs_space(vnode_t *vp, int cmd, flock64_t *bfp, int flag, return (EINVAL); } - if (error = convoff(vp, bfp, 0, offset)) { + if ((error = convoff(vp, bfp, 0, offset))) { ZFS_EXIT(zfsvfs); return (error); } @@ -4669,9 +4762,10 @@ zfs_space(vnode_t *vp, int cmd, flock64_t *bfp, int flag, ZFS_EXIT(zfsvfs); return (error); } +EXPORT_SYMBOL(zfs_space); /*ARGSUSED*/ -static int +int zfs_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct) { znode_t *zp = VTOZ(vp); @@ -4730,6 +4824,7 @@ zfs_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct) ZFS_EXIT(zfsvfs); return (0); } +EXPORT_SYMBOL(zfs_fid); static int zfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr, @@ -4802,7 +4897,7 @@ zfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr, } /*ARGSUSED*/ -static int +int zfs_getsecattr(vnode_t *vp, vsecattr_t *vsecp, int flag, cred_t *cr, caller_context_t *ct) { @@ -4818,9 +4913,10 @@ zfs_getsecattr(vnode_t *vp, vsecattr_t *vsecp, int flag, cred_t *cr, return (error); } +EXPORT_SYMBOL(zfs_getsecattr); /*ARGSUSED*/ -static int +int zfs_setsecattr(vnode_t *vp, vsecattr_t *vsecp, int flag, cred_t *cr, caller_context_t *ct) { @@ -4836,11 +4932,12 @@ zfs_setsecattr(vnode_t *vp, vsecattr_t *vsecp, int flag, cred_t *cr, error = zfs_setacl(zp, vsecp, skipaclchk, cr); if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS) - zil_commit(zilog, UINT64_MAX, 0); + zil_commit(zilog, 0); ZFS_EXIT(zfsvfs); return (error); } +EXPORT_SYMBOL(zfs_setsecattr); /* * Tunable, both must be a power of 2. @@ -5169,3 +5266,4 @@ const fs_operation_def_t zfs_evnodeops_template[] = { VOPNAME_PATHCONF, { .vop_pathconf = zfs_pathconf }, NULL, NULL }; +#endif /* HAVE_ZPL */