1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  23  */
  24 
  25 #include <sys/types.h>
  26 #include <sys/param.h>
  27 #include <sys/vnode.h>
  28 #include <sys/sa.h>
  29 #include <sys/zfs_acl.h>
  30 #include <sys/zfs_sa.h>
  31 
  32 /*
  33  * ZPL attribute registration table.
  34  * Order of attributes doesn't matter
  35  * a unique value will be assigned for each
  36  * attribute that is file system specific
  37  *
  38  * This is just the set of ZPL attributes that this
  39  * version of ZFS deals with natively.  The file system
  40  * could have other attributes stored in files, but they will be
  41  * ignored.  The SA framework will preserve them, just that
  42  * this version of ZFS won't change or delete them.
  43  */
  44 
  45 sa_attr_reg_t zfs_attr_table[ZPL_END+1] = {
  46         {"ZPL_ATIME", sizeof (uint64_t) * 2, SA_UINT64_ARRAY, 0},
  47         {"ZPL_MTIME", sizeof (uint64_t) * 2, SA_UINT64_ARRAY, 1},
  48         {"ZPL_CTIME", sizeof (uint64_t) * 2, SA_UINT64_ARRAY, 2},
  49         {"ZPL_CRTIME", sizeof (uint64_t) * 2, SA_UINT64_ARRAY, 3},
  50         {"ZPL_GEN", sizeof (uint64_t), SA_UINT64_ARRAY, 4},
  51         {"ZPL_MODE", sizeof (uint64_t), SA_UINT64_ARRAY, 5},
  52         {"ZPL_SIZE", sizeof (uint64_t), SA_UINT64_ARRAY, 6},
  53         {"ZPL_PARENT", sizeof (uint64_t), SA_UINT64_ARRAY, 7},
  54         {"ZPL_LINKS", sizeof (uint64_t), SA_UINT64_ARRAY, 8},
  55         {"ZPL_XATTR", sizeof (uint64_t), SA_UINT64_ARRAY, 9},
  56         {"ZPL_RDEV", sizeof (uint64_t), SA_UINT64_ARRAY, 10},
  57         {"ZPL_FLAGS", sizeof (uint64_t), SA_UINT64_ARRAY, 11},
  58         {"ZPL_UID", sizeof (uint64_t), SA_UINT64_ARRAY, 12},
  59         {"ZPL_GID", sizeof (uint64_t), SA_UINT64_ARRAY, 13},
  60         {"ZPL_PAD", sizeof (uint64_t) * 4, SA_UINT64_ARRAY, 14},
  61         {"ZPL_ZNODE_ACL", 88, SA_UINT8_ARRAY, 15},
  62         {"ZPL_DACL_COUNT", sizeof (uint64_t), SA_UINT64_ARRAY, 0},
  63         {"ZPL_SYMLINK", 0, SA_UINT8_ARRAY, 0},
  64         {"ZPL_SCANSTAMP", 32, SA_UINT8_ARRAY, 0},
  65         {"ZPL_DACL_ACES", 0, SA_ACL, 0},
  66         {NULL, 0, 0, 0}
  67 };
  68 
  69 #ifdef _KERNEL
  70 
  71 int
  72 zfs_sa_readlink(znode_t *zp, uio_t *uio)
  73 {
  74         dmu_buf_t *db = sa_get_db(zp->z_sa_hdl);
  75         size_t bufsz;
  76         int error;
  77 
  78         bufsz = zp->z_size;
  79         if (bufsz + ZFS_OLD_ZNODE_PHYS_SIZE <= db->db_size) {
  80                 error = uiomove((caddr_t)db->db_data +
  81                     ZFS_OLD_ZNODE_PHYS_SIZE,
  82                     MIN((size_t)bufsz, uio->uio_resid), UIO_READ, uio);
  83         } else {
  84                 dmu_buf_t *dbp;
  85                 if ((error = dmu_buf_hold(zp->z_zfsvfs->z_os, zp->z_id,
  86                     0, FTAG, &dbp, DMU_READ_NO_PREFETCH)) == 0) {
  87                         error = uiomove(dbp->db_data,
  88                             MIN((size_t)bufsz, uio->uio_resid), UIO_READ, uio);
  89                         dmu_buf_rele(dbp, FTAG);
  90                 }
  91         }
  92         return (error);
  93 }
  94 
  95 void
  96 zfs_sa_symlink(znode_t *zp, char *link, int len, dmu_tx_t *tx)
  97 {
  98         dmu_buf_t *db = sa_get_db(zp->z_sa_hdl);
  99 
 100         if (ZFS_OLD_ZNODE_PHYS_SIZE + len <= dmu_bonus_max()) {
 101                 VERIFY(dmu_set_bonus(db,
 102                     len + ZFS_OLD_ZNODE_PHYS_SIZE, tx) == 0);
 103                 if (len) {
 104                         bcopy(link, (caddr_t)db->db_data +
 105                             ZFS_OLD_ZNODE_PHYS_SIZE, len);
 106                 }
 107         } else {
 108                 dmu_buf_t *dbp;
 109 
 110                 zfs_grow_blocksize(zp, len, tx);
 111                 VERIFY(0 == dmu_buf_hold(zp->z_zfsvfs->z_os,
 112                     zp->z_id, 0, FTAG, &dbp, DMU_READ_NO_PREFETCH));
 113 
 114                 dmu_buf_will_dirty(dbp, tx);
 115 
 116                 ASSERT3U(len, <=, dbp->db_size);
 117                 bcopy(link, dbp->db_data, len);
 118                 dmu_buf_rele(dbp, FTAG);
 119         }
 120 }
 121 
 122 void
 123 zfs_sa_get_scanstamp(znode_t *zp, xvattr_t *xvap)
 124 {
 125         zfsvfs_t *zfsvfs = zp->z_zfsvfs;
 126         xoptattr_t *xoap;
 127 
 128         ASSERT(MUTEX_HELD(&zp->z_lock));
 129         VERIFY((xoap = xva_getxoptattr(xvap)) != NULL);
 130         if (zp->z_is_sa) {
 131                 if (sa_lookup(zp->z_sa_hdl, SA_ZPL_SCANSTAMP(zfsvfs),
 132                     &xoap->xoa_av_scanstamp,
 133                     sizeof (xoap->xoa_av_scanstamp)) != 0)
 134                         return;
 135         } else {
 136                 dmu_object_info_t doi;
 137                 dmu_buf_t *db = sa_get_db(zp->z_sa_hdl);
 138                 int len;
 139 
 140                 if (!(zp->z_pflags & ZFS_BONUS_SCANSTAMP))
 141                         return;
 142 
 143                 sa_object_info(zp->z_sa_hdl, &doi);
 144                 len = sizeof (xoap->xoa_av_scanstamp) +
 145                     ZFS_OLD_ZNODE_PHYS_SIZE;
 146 
 147                 if (len <= doi.doi_bonus_size) {
 148                         (void) memcpy(xoap->xoa_av_scanstamp,
 149                             (caddr_t)db->db_data + ZFS_OLD_ZNODE_PHYS_SIZE,
 150                             sizeof (xoap->xoa_av_scanstamp));
 151                 }
 152         }
 153         XVA_SET_RTN(xvap, XAT_AV_SCANSTAMP);
 154 }
 155 
 156 void
 157 zfs_sa_set_scanstamp(znode_t *zp, xvattr_t *xvap, dmu_tx_t *tx)
 158 {
 159         zfsvfs_t *zfsvfs = zp->z_zfsvfs;
 160         xoptattr_t *xoap;
 161 
 162         ASSERT(MUTEX_HELD(&zp->z_lock));
 163         VERIFY((xoap = xva_getxoptattr(xvap)) != NULL);
 164         if (zp->z_is_sa)
 165                 VERIFY(0 == sa_update(zp->z_sa_hdl, SA_ZPL_SCANSTAMP(zfsvfs),
 166                     &xoap->xoa_av_scanstamp,
 167                     sizeof (xoap->xoa_av_scanstamp), tx));
 168         else {
 169                 dmu_object_info_t doi;
 170                 dmu_buf_t *db = sa_get_db(zp->z_sa_hdl);
 171                 int len;
 172 
 173                 sa_object_info(zp->z_sa_hdl, &doi);
 174                 len = sizeof (xoap->xoa_av_scanstamp) +
 175                     ZFS_OLD_ZNODE_PHYS_SIZE;
 176                 if (len > doi.doi_bonus_size)
 177                         VERIFY(dmu_set_bonus(db, len, tx) == 0);
 178                 (void) memcpy((caddr_t)db->db_data + ZFS_OLD_ZNODE_PHYS_SIZE,
 179                     xoap->xoa_av_scanstamp, sizeof (xoap->xoa_av_scanstamp));
 180 
 181                 zp->z_pflags |= ZFS_BONUS_SCANSTAMP;
 182                 VERIFY(0 == sa_update(zp->z_sa_hdl, SA_ZPL_FLAGS(zfsvfs),
 183                     &zp->z_pflags, sizeof (uint64_t), tx));
 184         }
 185 }
 186 
 187 /*
 188  * I'm not convinced we should do any of this upgrade.
 189  * since the SA code can read both old/new znode formats
 190  * with probably little to no performance difference.
 191  *
 192  * All new files will be created with the new format.
 193  */
 194 
 195 void
 196 zfs_sa_upgrade(sa_handle_t *hdl, dmu_tx_t *tx)
 197 {
 198         dmu_buf_t *db = sa_get_db(hdl);
 199         znode_t *zp = sa_get_userdata(hdl);
 200         zfsvfs_t *zfsvfs = zp->z_zfsvfs;
 201         sa_bulk_attr_t bulk[20];
 202         int count = 0;
 203         sa_bulk_attr_t sa_attrs[20] = { 0 };
 204         zfs_acl_locator_cb_t locate = { 0 };
 205         uint64_t uid, gid, mode, rdev, xattr, parent;
 206         uint64_t crtime[2], mtime[2], ctime[2];
 207         zfs_acl_phys_t znode_acl;
 208         char scanstamp[AV_SCANSTAMP_SZ];
 209         boolean_t drop_lock = B_FALSE;
 210 
 211         /*
 212          * No upgrade if ACL isn't cached
 213          * since we won't know which locks are held
 214          * and ready the ACL would require special "locked"
 215          * interfaces that would be messy
 216          */
 217         if (zp->z_acl_cached == NULL || ZTOV(zp)->v_type == VLNK)
 218                 return;
 219 
 220         /*
 221          * If the z_lock is held and we aren't the owner
 222          * the just return since we don't want to deadlock
 223          * trying to update the status of z_is_sa.  This
 224          * file can then be upgraded at a later time.
 225          *
 226          * Otherwise, we know we are doing the
 227          * sa_update() that caused us to enter this function.
 228          */
 229         if (mutex_owner(&zp->z_lock) != curthread) {
 230                 if (mutex_tryenter(&zp->z_lock) == 0)
 231                         return;
 232                 else
 233                         drop_lock = B_TRUE;
 234         }
 235 
 236         /* First do a bulk query of the attributes that aren't cached */
 237         SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MTIME(zfsvfs), NULL, &mtime, 16);
 238         SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), NULL, &ctime, 16);
 239         SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CRTIME(zfsvfs), NULL, &crtime, 16);
 240         SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MODE(zfsvfs), NULL, &mode, 8);
 241         SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_PARENT(zfsvfs), NULL, &parent, 8);
 242         SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_XATTR(zfsvfs), NULL, &xattr, 8);
 243         SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_RDEV(zfsvfs), NULL, &rdev, 8);
 244         SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_UID(zfsvfs), NULL, &uid, 8);
 245         SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_GID(zfsvfs), NULL, &gid, 8);
 246         SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_ZNODE_ACL(zfsvfs), NULL,
 247             &znode_acl, 88);
 248 
 249         if (sa_bulk_lookup_locked(hdl, bulk, count) != 0)
 250                 goto done;
 251 
 252 
 253         /*
 254          * While the order here doesn't matter its best to try and organize
 255          * it is such a way to pick up an already existing layout number
 256          */
 257         count = 0;
 258         SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_MODE(zfsvfs), NULL, &mode, 8);
 259         SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_SIZE(zfsvfs), NULL,
 260             &zp->z_size, 8);
 261         SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_GEN(zfsvfs),
 262             NULL, &zp->z_gen, 8);
 263         SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_UID(zfsvfs), NULL, &uid, 8);
 264         SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_GID(zfsvfs), NULL, &gid, 8);
 265         SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_PARENT(zfsvfs),
 266             NULL, &parent, 8);
 267         SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_FLAGS(zfsvfs), NULL,
 268             &zp->z_pflags, 8);
 269         SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_ATIME(zfsvfs), NULL,
 270             zp->z_atime, 16);
 271         SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_MTIME(zfsvfs), NULL,
 272             &mtime, 16);
 273         SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_CTIME(zfsvfs), NULL,
 274             &ctime, 16);
 275         SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_CRTIME(zfsvfs), NULL,
 276             &crtime, 16);
 277         SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_LINKS(zfsvfs), NULL,
 278             &zp->z_links, 8);
 279         if (zp->z_vnode->v_type == VBLK || zp->z_vnode->v_type == VCHR)
 280                 SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_RDEV(zfsvfs), NULL,
 281                     &rdev, 8);
 282         SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_DACL_COUNT(zfsvfs), NULL,
 283             &zp->z_acl_cached->z_acl_count, 8);
 284 
 285         if (zp->z_acl_cached->z_version < ZFS_ACL_VERSION_FUID)
 286                 zfs_acl_xform(zp, zp->z_acl_cached, CRED());
 287 
 288         locate.cb_aclp = zp->z_acl_cached;
 289         SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_DACL_ACES(zfsvfs),
 290             zfs_acl_data_locator, &locate, zp->z_acl_cached->z_acl_bytes);
 291 
 292         if (xattr)
 293                 SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_XATTR(zfsvfs),
 294                     NULL, &xattr, 8);
 295 
 296         /* if scanstamp then add scanstamp */
 297 
 298         if (zp->z_pflags & ZFS_BONUS_SCANSTAMP) {
 299                 bcopy((caddr_t)db->db_data + ZFS_OLD_ZNODE_PHYS_SIZE,
 300                     scanstamp, AV_SCANSTAMP_SZ);
 301                 SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_SCANSTAMP(zfsvfs),
 302                     NULL, scanstamp, AV_SCANSTAMP_SZ);
 303                 zp->z_pflags &= ~ZFS_BONUS_SCANSTAMP;
 304         }
 305 
 306         VERIFY(dmu_set_bonustype(db, DMU_OT_SA, tx) == 0);
 307         VERIFY(sa_replace_all_by_template_locked(hdl, sa_attrs,
 308             count, tx) == 0);
 309         if (znode_acl.z_acl_extern_obj)
 310                 VERIFY(0 == dmu_object_free(zfsvfs->z_os,
 311                     znode_acl.z_acl_extern_obj, tx));
 312 
 313         zp->z_is_sa = B_TRUE;
 314 done:
 315         if (drop_lock)
 316                 mutex_exit(&zp->z_lock);
 317 }
 318 
 319 void
 320 zfs_sa_upgrade_txholds(dmu_tx_t *tx, znode_t *zp)
 321 {
 322         if (!zp->z_zfsvfs->z_use_sa || zp->z_is_sa)
 323                 return;
 324 
 325 
 326         dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE);
 327 
 328         if (zfs_external_acl(zp)) {
 329                 dmu_tx_hold_free(tx, zfs_external_acl(zp), 0,
 330                     DMU_OBJECT_END);
 331         }
 332 }
 333 
 334 #endif