* return (error); // done, report error
*/
+/*
+ * Virus scanning is unsupported. It would be possible to add a hook
+ * here to performance the required virus scan. This could be done
+ * entirely in the kernel or potentially as an update to invoke a
+ * scanning utility.
+ */
+static int
+zfs_vscan(struct inode *ip, cred_t *cr, int async)
+{
+ return (0);
+}
+
+/* ARGSUSED */
+int
+zfs_open(struct inode *ip, int mode, int flag, cred_t *cr)
+{
+ znode_t *zp = ITOZ(ip);
+ zfs_sb_t *zsb = ITOZSB(ip);
+
+ ZFS_ENTER(zsb);
+ ZFS_VERIFY_ZP(zp);
+
+ /* Honor ZFS_APPENDONLY file attribute */
+ if ((mode & FMODE_WRITE) && (zp->z_pflags & ZFS_APPENDONLY) &&
+ ((flag & O_APPEND) == 0)) {
+ ZFS_EXIT(zsb);
+ return (EPERM);
+ }
+
+ /* Virus scan eligible files on open */
+ if (!zfs_has_ctldir(zp) && zsb->z_vscan && S_ISREG(ip->i_mode) &&
+ !(zp->z_pflags & ZFS_AV_QUARANTINED) && zp->z_size > 0) {
+ if (zfs_vscan(ip, cr, 0) != 0) {
+ ZFS_EXIT(zsb);
+ return (EACCES);
+ }
+ }
+
+ /* Keep a count of the synchronous opens in the znode */
+ if (flag & O_SYNC)
+ atomic_inc_32(&zp->z_sync_cnt);
+
+ ZFS_EXIT(zsb);
+ return (0);
+}
+EXPORT_SYMBOL(zfs_open);
+
+/* ARGSUSED */
+int
+zfs_close(struct inode *ip, int flag, cred_t *cr)
+{
+ znode_t *zp = ITOZ(ip);
+ zfs_sb_t *zsb = ITOZSB(ip);
+
+ ZFS_ENTER(zsb);
+ ZFS_VERIFY_ZP(zp);
+
+ /* Decrement the synchronous opens in the znode */
+ if (flag & O_SYNC)
+ zp->z_sync_cnt = 0;
+
+ if (!zfs_has_ctldir(zp) && zsb->z_vscan && S_ISREG(ip->i_mode) &&
+ !(zp->z_pflags & ZFS_AV_QUARANTINED) && zp->z_size > 0)
+ VERIFY(zfs_vscan(ip, cr, 1) == 0);
+
+ ZFS_EXIT(zsb);
+ return (0);
+}
+EXPORT_SYMBOL(zfs_close);
+
#if defined(_KERNEL)
/*
* When a file is memory mapped, we must keep the IO data synchronized
return (EILSEQ);
}
-#ifdef HAVE_XVATTR
- if (vap->va_mask & AT_XVATTR) {
+ if (vap->va_mask & ATTR_XVATTR) {
if ((error = secpolicy_xvattr((xvattr_t *)vap,
crgetuid(cr), cr, vap->va_mode)) != 0) {
ZFS_EXIT(zsb);
return (error);
}
}
-#endif /* HAVE_XVATTR */
top:
*ipp = NULL;
if (flags & FIGNORECASE)
zf |= ZCILOOK;
-#ifdef HAVE_XVATTR
- if (vap->va_mask & AT_XVATTR) {
+ if (vap->va_mask & ATTR_XVATTR) {
if ((error = secpolicy_xvattr((xvattr_t *)vap,
crgetuid(cr), cr, vap->va_mode)) != 0) {
ZFS_EXIT(zsb);
return (error);
}
}
-#endif /* HAVE_XVATTR */
if ((error = zfs_acl_ids_create(dzp, 0, vap, cr,
vsecp, &acl_ids)) != 0) {
* vattr structure.
*
* IN: ip - inode of file.
- * stat - kstat structure to fill in.
+ * vap - va_mask identifies requested attributes.
+ * If ATTR_XVATTR set, then optional attrs are requested
* flags - ATTR_NOACLCHECK (CIFS server context)
* cr - credentials of caller.
*
- * OUT: stat - filled in kstat values.
+ * OUT: vap - attribute values.
+ *
+ * RETURN: 0 (always succeeds)
*/
/* ARGSUSED */
int
-zfs_getattr(struct inode *ip, struct kstat *stat, int flags, cred_t *cr)
+zfs_getattr(struct inode *ip, vattr_t *vap, int flags, cred_t *cr)
{
znode_t *zp = ITOZ(ip);
zfs_sb_t *zsb = ITOZSB(ip);
int error = 0;
uint64_t links;
uint64_t mtime[2], ctime[2];
- uint32_t blksz;
+ xvattr_t *xvap = (xvattr_t *)vap; /* vap may be an xvattr_t * */
+ xoptattr_t *xoap = NULL;
boolean_t skipaclchk = (flags & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE;
sa_bulk_attr_t bulk[2];
int count = 0;
ZFS_ENTER(zsb);
ZFS_VERIFY_ZP(zp);
- zfs_fuid_map_ids(zp, cr, &stat->uid, &stat->gid);
+ zfs_fuid_map_ids(zp, cr, &vap->va_uid, &vap->va_gid);
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MTIME(zsb), NULL, &mtime, 16);
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zsb), NULL, &ctime, 16);
* always be allowed to read basic attributes of file.
*/
if (!(zp->z_pflags & ZFS_ACL_TRIVIAL) &&
- (stat->uid != crgetuid(cr))) {
+ (vap->va_uid != crgetuid(cr))) {
if ((error = zfs_zaccess(zp, ACE_READ_ATTRIBUTES, 0,
skipaclchk, cr))) {
ZFS_EXIT(zsb);
*/
mutex_enter(&zp->z_lock);
- stat->ino = ip->i_ino;
- stat->mode = zp->z_mode;
- stat->uid = zp->z_uid;
- stat->gid = zp->z_gid;
+ vap->va_type = vn_mode_to_vtype(zp->z_mode);
+ vap->va_mode = zp->z_mode;
+ vap->va_fsid = ZTOI(zp)->i_sb->s_dev;
+ vap->va_nodeid = zp->z_id;
if ((zp->z_id == zsb->z_root) && zfs_show_ctldir(zp))
links = zp->z_links + 1;
else
links = zp->z_links;
- stat->nlink = MIN(links, ZFS_LINK_MAX);
- stat->size = i_size_read(ip);
- stat->rdev = ip->i_rdev;
- stat->dev = ip->i_rdev;
+ vap->va_nlink = MIN(links, ZFS_LINK_MAX);
+ vap->va_size = i_size_read(ip);
+ vap->va_rdev = ip->i_rdev;
+ vap->va_seq = ip->i_generation;
- ZFS_TIME_DECODE(&stat->atime, zp->z_atime);
- ZFS_TIME_DECODE(&stat->mtime, mtime);
- ZFS_TIME_DECODE(&stat->ctime, ctime);
+ /*
+ * Add in any requested optional attributes and the create time.
+ * Also set the corresponding bits in the returned attribute bitmap.
+ */
+ if ((xoap = xva_getxoptattr(xvap)) != NULL && zsb->z_use_fuids) {
+ if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE)) {
+ xoap->xoa_archive =
+ ((zp->z_pflags & ZFS_ARCHIVE) != 0);
+ XVA_SET_RTN(xvap, XAT_ARCHIVE);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_READONLY)) {
+ xoap->xoa_readonly =
+ ((zp->z_pflags & ZFS_READONLY) != 0);
+ XVA_SET_RTN(xvap, XAT_READONLY);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_SYSTEM)) {
+ xoap->xoa_system =
+ ((zp->z_pflags & ZFS_SYSTEM) != 0);
+ XVA_SET_RTN(xvap, XAT_SYSTEM);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_HIDDEN)) {
+ xoap->xoa_hidden =
+ ((zp->z_pflags & ZFS_HIDDEN) != 0);
+ XVA_SET_RTN(xvap, XAT_HIDDEN);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_NOUNLINK)) {
+ xoap->xoa_nounlink =
+ ((zp->z_pflags & ZFS_NOUNLINK) != 0);
+ XVA_SET_RTN(xvap, XAT_NOUNLINK);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE)) {
+ xoap->xoa_immutable =
+ ((zp->z_pflags & ZFS_IMMUTABLE) != 0);
+ XVA_SET_RTN(xvap, XAT_IMMUTABLE);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_APPENDONLY)) {
+ xoap->xoa_appendonly =
+ ((zp->z_pflags & ZFS_APPENDONLY) != 0);
+ XVA_SET_RTN(xvap, XAT_APPENDONLY);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_NODUMP)) {
+ xoap->xoa_nodump =
+ ((zp->z_pflags & ZFS_NODUMP) != 0);
+ XVA_SET_RTN(xvap, XAT_NODUMP);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_OPAQUE)) {
+ xoap->xoa_opaque =
+ ((zp->z_pflags & ZFS_OPAQUE) != 0);
+ XVA_SET_RTN(xvap, XAT_OPAQUE);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED)) {
+ xoap->xoa_av_quarantined =
+ ((zp->z_pflags & ZFS_AV_QUARANTINED) != 0);
+ XVA_SET_RTN(xvap, XAT_AV_QUARANTINED);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED)) {
+ xoap->xoa_av_modified =
+ ((zp->z_pflags & ZFS_AV_MODIFIED) != 0);
+ XVA_SET_RTN(xvap, XAT_AV_MODIFIED);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP) &&
+ S_ISREG(ip->i_mode)) {
+ zfs_sa_get_scanstamp(zp, xvap);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_CREATETIME)) {
+ uint64_t times[2];
+
+ (void) sa_lookup(zp->z_sa_hdl, SA_ZPL_CRTIME(zsb),
+ times, sizeof (times));
+ ZFS_TIME_DECODE(&xoap->xoa_createtime, times);
+ XVA_SET_RTN(xvap, XAT_CREATETIME);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_REPARSE)) {
+ 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);
+ ZFS_TIME_DECODE(&vap->va_mtime, mtime);
+ ZFS_TIME_DECODE(&vap->va_ctime, ctime);
mutex_exit(&zp->z_lock);
- sa_object_size(zp->z_sa_hdl, &blksz, &stat->blocks);
- stat->blksize = (1 << ip->i_blkbits);
+ sa_object_size(zp->z_sa_hdl, &vap->va_blksize, &vap->va_nblocks);
if (zp->z_blksz == 0) {
/*
* Block size hasn't been set; suggest maximal I/O transfers.
*/
- stat->blksize = zsb->z_max_blksz;
+ vap->va_blksize = zsb->z_max_blksz;
}
ZFS_EXIT(zsb);
*
* IN: ip - inode of file to be modified.
* vap - new attribute values.
- * If AT_XVATTR set, then optional attrs are being set
+ * If ATTR_XVATTR set, then optional attrs are being set
* flags - ATTR_UTIME set if non-default time values provided.
* - ATTR_NOACLCHECK (CIFS context only).
* cr - credentials of caller.
*/
/* ARGSUSED */
int
-zfs_setattr(struct inode *ip, struct iattr *attr, int flags, cred_t *cr)
+zfs_setattr(struct inode *ip, vattr_t *vap, int flags, cred_t *cr)
{
znode_t *zp = ITOZ(ip);
zfs_sb_t *zsb = ITOZSB(ip);
zilog_t *zilog;
dmu_tx_t *tx;
vattr_t oldva;
- uint_t mask = attr->ia_valid;
+ xvattr_t *tmpxvattr;
+ uint_t mask = vap->va_mask;
uint_t saved_mask;
int trim_mask = 0;
uint64_t new_mode;
int need_policy = FALSE;
int err, err2;
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;
boolean_t skipaclchk = (flags & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE;
- zfs_acl_t *aclp = NULL;
boolean_t fuid_dirtied = B_FALSE;
- sa_bulk_attr_t bulk[7], xattr_bulk[7];
+ sa_bulk_attr_t *bulk, *xattr_bulk;
int count = 0, xattr_count = 0;
if (mask == 0)
* Make sure that if we have ephemeral uid/gid or xvattr specified
* that file system is at proper version level
*/
+
if (zsb->z_use_fuids == B_FALSE &&
- (((mask & ATTR_UID) && IS_EPHEMERAL(attr->ia_uid)) ||
- ((mask & ATTR_GID) && IS_EPHEMERAL(attr->ia_gid)))) {
+ (((mask & ATTR_UID) && IS_EPHEMERAL(vap->va_uid)) ||
+ ((mask & ATTR_GID) && IS_EPHEMERAL(vap->va_gid)) ||
+ (mask & ATTR_XVATTR))) {
ZFS_EXIT(zsb);
return (EINVAL);
}
return (EINVAL);
}
+ /*
+ * If this is an xvattr_t, then get a pointer to the structure of
+ * optional attributes. If this is NULL, then we have a vattr_t.
+ */
+ xoap = xva_getxoptattr(xvap);
+
+ tmpxvattr = kmem_alloc(sizeof(xvattr_t), KM_SLEEP);
+ xva_init(tmpxvattr);
+
+ bulk = kmem_alloc(sizeof(sa_bulk_attr_t) * 7, KM_SLEEP);
+ xattr_bulk = kmem_alloc(sizeof(sa_bulk_attr_t) * 7, KM_SLEEP);
+
+ /*
+ * Immutable files can only alter immutable bit and atime
+ */
+ if ((zp->z_pflags & ZFS_IMMUTABLE) &&
+ ((mask & (ATTR_SIZE|ATTR_UID|ATTR_GID|ATTR_MTIME|ATTR_MODE)) ||
+ ((mask & ATTR_XVATTR) && XVA_ISSET_REQ(xvap, XAT_CREATETIME)))) {
+ err = EPERM;
+ goto out3;
+ }
+
if ((mask & ATTR_SIZE) && (zp->z_pflags & ZFS_READONLY)) {
- ZFS_EXIT(zsb);
- return (EPERM);
+ err = EPERM;
+ goto out3;
+ }
+
+ /*
+ * Verify timestamps doesn't overflow 32 bits.
+ * ZFS can handle large timestamps, but 32bit syscalls can't
+ * handle times greater than 2039. This check should be removed
+ * once large timestamps are fully supported.
+ */
+ if (mask & (ATTR_ATIME | ATTR_MTIME)) {
+ if (((mask & ATTR_ATIME) && TIMESPEC_OVERFLOW(&vap->va_atime)) ||
+ ((mask & ATTR_MTIME) && TIMESPEC_OVERFLOW(&vap->va_mtime))) {
+ err = EOVERFLOW;
+ goto out3;
+ }
}
top:
/* Can this be moved to before the top label? */
if (zsb->z_vfs->mnt_flags & MNT_READONLY) {
- ZFS_EXIT(zsb);
- return (EROFS);
+ err = EROFS;
+ goto out3;
}
/*
if (mask & ATTR_SIZE) {
err = zfs_zaccess(zp, ACE_WRITE_DATA, 0, skipaclchk, cr);
- if (err) {
- ZFS_EXIT(zsb);
- return (err);
- }
+ if (err)
+ goto out3;
+
/*
* XXX - Note, we are not providing any open
* mode flags here (like FNDELAY), so we may
* should be addressed in openat().
*/
/* XXX - would it be OK to generate a log record here? */
- err = zfs_freesp(zp, attr->ia_size, 0, 0, FALSE);
- if (err) {
- ZFS_EXIT(zsb);
- return (err);
- }
+ err = zfs_freesp(zp, vap->va_size, 0, 0, FALSE);
+ if (err)
+ goto out3;
/* Careful negative Linux return code here */
- err = -vmtruncate(ip, attr->ia_size);
- if (err) {
- ZFS_EXIT(zsb);
- return (err);
- }
+ err = -vmtruncate(ip, vap->va_size);
+ if (err)
+ goto out3;
+ }
+
+ if (mask & (ATTR_ATIME|ATTR_MTIME) ||
+ ((mask & ATTR_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,
+ skipaclchk, cr);
}
if (mask & (ATTR_UID|ATTR_GID)) {
*/
if (!(mask & ATTR_MODE))
- attr->ia_mode = zp->z_mode;
+ vap->va_mode = zp->z_mode;
/*
* Take ownership or chgrp to group we are a member of
*/
- take_owner = (mask & ATTR_UID) &&
- (attr->ia_uid == crgetuid(cr));
+ take_owner = (mask & ATTR_UID) && (vap->va_uid == crgetuid(cr));
take_group = (mask & ATTR_GID) &&
- zfs_groupmember(zsb, attr->ia_gid, cr);
+ zfs_groupmember(zsb, vap->va_gid, cr);
/*
- * If both AT_UID and AT_GID are set then take_owner and
+ * If both ATTR_UID and ATTR_GID are set then take_owner and
* take_group must both be set in order to allow taking
* ownership.
*
/*
* Remove setuid/setgid for non-privileged users
*/
- secpolicy_setid_clear(attr, cr);
+ (void) secpolicy_setid_clear(vap, cr);
trim_mask = (mask & (ATTR_UID|ATTR_GID));
} else {
need_policy = TRUE;
mutex_enter(&zp->z_lock);
oldva.va_mode = zp->z_mode;
zfs_fuid_map_ids(zp, cr, &oldva.va_uid, &oldva.va_gid);
+ if (mask & ATTR_XVATTR) {
+ /*
+ * Update xvattr mask to include only those attributes
+ * that are actually changing.
+ *
+ * the bits will be restored prior to actually setting
+ * the attributes so the caller thinks they were set.
+ */
+ if (XVA_ISSET_REQ(xvap, XAT_APPENDONLY)) {
+ if (xoap->xoa_appendonly !=
+ ((zp->z_pflags & ZFS_APPENDONLY) != 0)) {
+ need_policy = TRUE;
+ } else {
+ XVA_CLR_REQ(xvap, XAT_APPENDONLY);
+ XVA_SET_REQ(tmpxvattr, XAT_APPENDONLY);
+ }
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_NOUNLINK)) {
+ if (xoap->xoa_nounlink !=
+ ((zp->z_pflags & ZFS_NOUNLINK) != 0)) {
+ need_policy = TRUE;
+ } else {
+ XVA_CLR_REQ(xvap, XAT_NOUNLINK);
+ XVA_SET_REQ(tmpxvattr, XAT_NOUNLINK);
+ }
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE)) {
+ if (xoap->xoa_immutable !=
+ ((zp->z_pflags & ZFS_IMMUTABLE) != 0)) {
+ need_policy = TRUE;
+ } else {
+ XVA_CLR_REQ(xvap, XAT_IMMUTABLE);
+ XVA_SET_REQ(tmpxvattr, XAT_IMMUTABLE);
+ }
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_NODUMP)) {
+ if (xoap->xoa_nodump !=
+ ((zp->z_pflags & ZFS_NODUMP) != 0)) {
+ need_policy = TRUE;
+ } else {
+ XVA_CLR_REQ(xvap, XAT_NODUMP);
+ XVA_SET_REQ(tmpxvattr, XAT_NODUMP);
+ }
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED)) {
+ if (xoap->xoa_av_modified !=
+ ((zp->z_pflags & ZFS_AV_MODIFIED) != 0)) {
+ need_policy = TRUE;
+ } else {
+ XVA_CLR_REQ(xvap, XAT_AV_MODIFIED);
+ XVA_SET_REQ(tmpxvattr, XAT_AV_MODIFIED);
+ }
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED)) {
+ if ((!S_ISREG(ip->i_mode) &&
+ xoap->xoa_av_quarantined) ||
+ xoap->xoa_av_quarantined !=
+ ((zp->z_pflags & ZFS_AV_QUARANTINED) != 0)) {
+ need_policy = TRUE;
+ } else {
+ XVA_CLR_REQ(xvap, XAT_AV_QUARANTINED);
+ XVA_SET_REQ(tmpxvattr, XAT_AV_QUARANTINED);
+ }
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_REPARSE)) {
+ mutex_exit(&zp->z_lock);
+ err = EPERM;
+ goto out3;
+ }
+
+ if (need_policy == FALSE &&
+ (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP) ||
+ XVA_ISSET_REQ(xvap, XAT_OPAQUE))) {
+ need_policy = TRUE;
+ }
+ }
mutex_exit(&zp->z_lock);
if (mask & ATTR_MODE) {
if (zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr) == 0) {
- err = secpolicy_setid_setsticky_clear(ip, attr,
+ err = secpolicy_setid_setsticky_clear(ip, vap,
&oldva, cr);
- if (err) {
- ZFS_EXIT(zsb);
- return (err);
- }
+ if (err)
+ goto out3;
+
trim_mask |= ATTR_MODE;
} else {
need_policy = TRUE;
*/
if (trim_mask) {
- saved_mask = attr->ia_valid;
- attr->ia_valid &= ~trim_mask;
+ saved_mask = vap->va_mask;
+ vap->va_mask &= ~trim_mask;
}
- err = secpolicy_vnode_setattr(cr, ip, attr, &oldva, flags,
+ err = secpolicy_vnode_setattr(cr, ip, vap, &oldva, flags,
(int (*)(void *, int, cred_t *))zfs_zaccess_unix, zp);
- if (err) {
- ZFS_EXIT(zsb);
- return (err);
- }
+ if (err)
+ goto out3;
if (trim_mask)
- attr->ia_valid |= saved_mask;
+ vap->va_mask |= saved_mask;
}
/*
* secpolicy_vnode_setattr, or take ownership may have
* changed va_mask
*/
- mask = attr->ia_valid;
+ mask = vap->va_mask;
if ((mask & (ATTR_UID | ATTR_GID))) {
err = sa_lookup(zp->z_sa_hdl, SA_ZPL_XATTR(zsb),
}
if (mask & ATTR_UID) {
new_uid = zfs_fuid_create(zsb,
- (uint64_t)attr->ia_uid, cr, ZFS_OWNER, &fuidp);
+ (uint64_t)vap->va_uid, cr, ZFS_OWNER, &fuidp);
if (new_uid != zp->z_uid &&
zfs_fuid_overquota(zsb, B_FALSE, new_uid)) {
if (attrzp)
}
if (mask & ATTR_GID) {
- new_gid = zfs_fuid_create(zsb, (uint64_t)attr->ia_gid,
+ new_gid = zfs_fuid_create(zsb, (uint64_t)vap->va_gid,
cr, ZFS_GROUP, &fuidp);
if (new_gid != zp->z_gid &&
zfs_fuid_overquota(zsb, B_TRUE, new_gid)) {
if (mask & ATTR_MODE) {
uint64_t pmode = zp->z_mode;
uint64_t acl_obj;
- new_mode = (pmode & S_IFMT) | (attr->ia_mode & ~S_IFMT);
+ new_mode = (pmode & S_IFMT) | (vap->va_mode & ~S_IFMT);
zfs_acl_chmod_setattr(zp, &aclp, new_mode);
mutex_exit(&zp->z_lock);
dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE);
} else {
- dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
+ if ((mask & ATTR_XVATTR) &&
+ XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP))
+ dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE);
+ else
+ dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
}
if (attrzp) {
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MODE(zsb), NULL,
&new_mode, sizeof (new_mode));
zp->z_mode = new_mode;
- ASSERT3U((uintptr_t)aclp, !=, NULL);
+ ASSERT3P(aclp, !=, NULL);
err = zfs_aclset_common(zp, aclp, cr, tx);
ASSERT3U(err, ==, 0);
if (zp->z_acl_cached)
if (mask & ATTR_ATIME) {
- ZFS_TIME_ENCODE(&attr->ia_atime, zp->z_atime);
+ ZFS_TIME_ENCODE(&vap->va_atime, zp->z_atime);
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_ATIME(zsb), NULL,
&zp->z_atime, sizeof (zp->z_atime));
}
if (mask & ATTR_MTIME) {
- ZFS_TIME_ENCODE(&attr->ia_mtime, mtime);
+ ZFS_TIME_ENCODE(&vap->va_mtime, mtime);
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MTIME(zsb), NULL,
mtime, sizeof (mtime));
}
* update from toggling bit
*/
+ if (xoap && (mask & ATTR_XVATTR)) {
+
+ /*
+ * restore trimmed off masks
+ * so that return masks can be set for caller.
+ */
+
+ if (XVA_ISSET_REQ(tmpxvattr, XAT_APPENDONLY)) {
+ XVA_SET_REQ(xvap, XAT_APPENDONLY);
+ }
+ if (XVA_ISSET_REQ(tmpxvattr, XAT_NOUNLINK)) {
+ XVA_SET_REQ(xvap, XAT_NOUNLINK);
+ }
+ if (XVA_ISSET_REQ(tmpxvattr, XAT_IMMUTABLE)) {
+ XVA_SET_REQ(xvap, XAT_IMMUTABLE);
+ }
+ if (XVA_ISSET_REQ(tmpxvattr, XAT_NODUMP)) {
+ XVA_SET_REQ(xvap, XAT_NODUMP);
+ }
+ if (XVA_ISSET_REQ(tmpxvattr, XAT_AV_MODIFIED)) {
+ XVA_SET_REQ(xvap, XAT_AV_MODIFIED);
+ }
+ if (XVA_ISSET_REQ(tmpxvattr, XAT_AV_QUARANTINED)) {
+ XVA_SET_REQ(xvap, XAT_AV_QUARANTINED);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP))
+ ASSERT(S_ISREG(ip->i_mode));
+
+ zfs_xvattr_set(zp, xvap, tx);
+ }
+
if (fuid_dirtied)
zfs_fuid_sync(zsb, tx);
if (mask != 0)
- zfs_log_setattr(zilog, tx, TX_SETATTR, zp, attr, mask, fuidp);
+ zfs_log_setattr(zilog, tx, TX_SETATTR, zp, vap, mask, fuidp);
mutex_exit(&zp->z_lock);
if (mask & (ATTR_UID|ATTR_GID|ATTR_MODE))
} else {
err2 = sa_bulk_update(zp->z_sa_hdl, bulk, count, tx);
dmu_tx_commit(tx);
- zfs_inode_update(zp);
+ zfs_inode_update(zp);
}
out2:
if (zsb->z_os->os_sync == ZFS_SYNC_ALWAYS)
zil_commit(zilog, 0);
+out3:
+ kmem_free(xattr_bulk, sizeof(sa_bulk_attr_t) * 7);
+ kmem_free(bulk, sizeof(sa_bulk_attr_t) * 7);
+ kmem_free(tmpxvattr, sizeof(xvattr_t));
ZFS_EXIT(zsb);
return (err);
}
zfs_dirent_unlock(dl);
*ipp = ZTOI(zp);
- iput(ZTOI(zp));
if (zsb->z_os->os_sync == ZFS_SYNC_ALWAYS)
zil_commit(zilog, 0);
* Return, in the buffer contained in the provided uio structure,
* the symbolic path referred to by ip.
*
- * IN: dentry - dentry of symbolic link.
- * nd - namedata for symlink
+ * IN: ip - inode of symbolic link
+ * uio - structure to contain the link path.
+ * cr - credentials of caller.
*
* RETURN: 0 if success
* error code if failure
*/
/* ARGSUSED */
int
-zfs_follow_link(struct dentry *dentry, struct nameidata *nd)
+zfs_readlink(struct inode *ip, uio_t *uio, cred_t *cr)
{
- struct inode *ip = dentry->d_inode;
znode_t *zp = ITOZ(ip);
zfs_sb_t *zsb = ITOZSB(ip);
- struct iovec iov;
- uio_t uio;
int error;
ZFS_ENTER(zsb);
ZFS_VERIFY_ZP(zp);
- iov.iov_len = MAXPATHLEN + 1;
- iov.iov_base = kmem_zalloc(iov.iov_len, KM_SLEEP);
-
- uio.uio_iov = &iov;
- uio.uio_iovcnt = 1;
- uio.uio_resid = iov.iov_len;
- uio.uio_segflg = UIO_SYSSPACE;
-
mutex_enter(&zp->z_lock);
if (zp->z_is_sa)
- error = sa_lookup_uio(zp->z_sa_hdl, SA_ZPL_SYMLINK(zsb), &uio);
+ error = sa_lookup_uio(zp->z_sa_hdl,
+ SA_ZPL_SYMLINK(zsb), uio);
else
- error = zfs_sa_readlink(zp, &uio);
+ error = zfs_sa_readlink(zp, uio);
mutex_exit(&zp->z_lock);
ZFS_ACCESSTIME_STAMP(zsb, zp);
zfs_inode_update(zp);
-
- if (error) {
- kmem_free(iov.iov_base, iov.iov_len);
- nd_set_link(nd, ERR_PTR(error));
- } else {
- nd_set_link(nd, iov.iov_base);
- }
-
ZFS_EXIT(zsb);
return (error);
}
-EXPORT_SYMBOL(zfs_follow_link);
+EXPORT_SYMBOL(zfs_readlink);
/*
* Insert a new entry into directory tdip referencing sip.
*/
/*ARGSUSED*/
static int
-zfs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
- caller_context_t *ct)
+zfs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
*/
/* ARGSUSED */
int
-zfs_seek(struct inode *ip, offset_t ooff, offset_t *noffp,
- caller_context_t *ct)
+zfs_seek(struct inode *ip, offset_t ooff, offset_t *noffp)
{
if (S_ISDIR(ip->i_mode))
return (0);
*/
static int
zfs_frlock(vnode_t *vp, int cmd, flock64_t *bfp, int flag, offset_t offset,
- flk_callback_t *flk_cbp, cred_t *cr, caller_context_t *ct)
+ flk_callback_t *flk_cbp, cred_t *cr)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
static int
zfs_getpage(vnode_t *vp, offset_t off, size_t len, uint_t *protp,
page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr,
- enum seg_rw rw, cred_t *cr, caller_context_t *ct)
+ enum seg_rw rw, cred_t *cr)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
/*ARGSUSED*/
static int
zfs_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
- size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
- caller_context_t *ct)
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
/* ARGSUSED */
static int
zfs_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
- size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
- caller_context_t *ct)
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr)
{
uint64_t pages = btopr(len);
/* ARGSUSED */
static int
zfs_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
- size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr,
- caller_context_t *ct)
+ size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr)
{
uint64_t pages = btopr(len);
int
convoff(struct inode *ip, flock64_t *lckdat, int whence, offset_t offset)
{
- struct kstat stat;
+ vattr_t vap;
int error;
if ((lckdat->l_whence == 2) || (whence == 2)) {
- if ((error = zfs_getattr(ip, &stat, 0, CRED()) != 0))
+ if ((error = zfs_getattr(ip, &vap, 0, CRED()) != 0))
return (error);
}
lckdat->l_start += offset;
break;
case 2:
- lckdat->l_start += stat.size;
+ lckdat->l_start += vap.va_size;
/* FALLTHRU */
case 0:
break;
lckdat->l_start -= offset;
break;
case 2:
- lckdat->l_start -= stat.size;
+ lckdat->l_start -= vap.va_size;
/* FALLTHRU */
case 0:
break;