1*da6c28aaSamw /* 2*da6c28aaSamw * CDDL HEADER START 3*da6c28aaSamw * 4*da6c28aaSamw * The contents of this file are subject to the terms of the 5*da6c28aaSamw * Common Development and Distribution License (the "License"). 6*da6c28aaSamw * You may not use this file except in compliance with the License. 7*da6c28aaSamw * 8*da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10*da6c28aaSamw * See the License for the specific language governing permissions 11*da6c28aaSamw * and limitations under the License. 12*da6c28aaSamw * 13*da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14*da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16*da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17*da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18*da6c28aaSamw * 19*da6c28aaSamw * CDDL HEADER END 20*da6c28aaSamw */ 21*da6c28aaSamw /* 22*da6c28aaSamw * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23*da6c28aaSamw * Use is subject to license terms. 24*da6c28aaSamw */ 25*da6c28aaSamw 26*da6c28aaSamw #pragma ident "%Z%%M% %I% %E% SMI" 27*da6c28aaSamw 28*da6c28aaSamw #include <sys/param.h> 29*da6c28aaSamw #include <sys/isa_defs.h> 30*da6c28aaSamw #include <sys/types.h> 31*da6c28aaSamw #include <sys/sysmacros.h> 32*da6c28aaSamw #include <sys/cred.h> 33*da6c28aaSamw #include <sys/systm.h> 34*da6c28aaSamw #include <sys/errno.h> 35*da6c28aaSamw #include <sys/fcntl.h> 36*da6c28aaSamw #include <sys/pathname.h> 37*da6c28aaSamw #include <sys/stat.h> 38*da6c28aaSamw #include <sys/vfs.h> 39*da6c28aaSamw #include <sys/acl.h> 40*da6c28aaSamw #include <sys/file.h> 41*da6c28aaSamw #include <sys/sunddi.h> 42*da6c28aaSamw #include <sys/debug.h> 43*da6c28aaSamw #include <sys/cmn_err.h> 44*da6c28aaSamw #include <sys/vnode.h> 45*da6c28aaSamw #include <sys/mode.h> 46*da6c28aaSamw #include <sys/nvpair.h> 47*da6c28aaSamw #include <sys/attr.h> 48*da6c28aaSamw #include <sys/gfs.h> 49*da6c28aaSamw #include <sys/mutex.h> 50*da6c28aaSamw #include <fs/fs_subr.h> 51*da6c28aaSamw #include <sys/kidmap.h> 52*da6c28aaSamw 53*da6c28aaSamw typedef struct { 54*da6c28aaSamw gfs_file_t gfs_private; 55*da6c28aaSamw xattr_view_t xattr_view; 56*da6c28aaSamw } xattr_file_t; 57*da6c28aaSamw 58*da6c28aaSamw /* ARGSUSED */ 59*da6c28aaSamw static int 60*da6c28aaSamw xattr_file_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct) 61*da6c28aaSamw { 62*da6c28aaSamw xattr_file_t *np = (*vpp)->v_data; 63*da6c28aaSamw 64*da6c28aaSamw if ((np->xattr_view == XATTR_VIEW_READONLY) && (flags & FWRITE)) 65*da6c28aaSamw return (EACCES); 66*da6c28aaSamw 67*da6c28aaSamw return (0); 68*da6c28aaSamw } 69*da6c28aaSamw 70*da6c28aaSamw /* ARGSUSED */ 71*da6c28aaSamw static int 72*da6c28aaSamw xattr_file_access(vnode_t *vp, int mode, int flags, cred_t *cr, 73*da6c28aaSamw caller_context_t *ct) 74*da6c28aaSamw { 75*da6c28aaSamw xattr_file_t *np = vp->v_data; 76*da6c28aaSamw 77*da6c28aaSamw if ((np->xattr_view == XATTR_VIEW_READONLY) && (mode & VWRITE)) 78*da6c28aaSamw return (EACCES); 79*da6c28aaSamw 80*da6c28aaSamw return (0); 81*da6c28aaSamw } 82*da6c28aaSamw 83*da6c28aaSamw /* ARGSUSED */ 84*da6c28aaSamw static int 85*da6c28aaSamw xattr_file_close(vnode_t *vp, int flags, int count, offset_t off, 86*da6c28aaSamw cred_t *cr, caller_context_t *ct) 87*da6c28aaSamw { 88*da6c28aaSamw cleanlocks(vp, ddi_get_pid(), 0); 89*da6c28aaSamw cleanshares(vp, ddi_get_pid()); 90*da6c28aaSamw return (0); 91*da6c28aaSamw } 92*da6c28aaSamw 93*da6c28aaSamw static int 94*da6c28aaSamw xattr_common_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct) 95*da6c28aaSamw { 96*da6c28aaSamw xattr_fid_t *xfidp; 97*da6c28aaSamw vnode_t *pvp, *savevp; 98*da6c28aaSamw int error; 99*da6c28aaSamw uint16_t orig_len; 100*da6c28aaSamw 101*da6c28aaSamw if (fidp->fid_len < XATTR_FIDSZ) { 102*da6c28aaSamw fidp->fid_len = XATTR_FIDSZ; 103*da6c28aaSamw return (ENOSPC); 104*da6c28aaSamw } 105*da6c28aaSamw 106*da6c28aaSamw savevp = pvp = gfs_file_parent(vp); 107*da6c28aaSamw mutex_enter(&savevp->v_lock); 108*da6c28aaSamw if (pvp->v_flag & V_XATTRDIR) { 109*da6c28aaSamw pvp = gfs_file_parent(pvp); 110*da6c28aaSamw } 111*da6c28aaSamw mutex_exit(&savevp->v_lock); 112*da6c28aaSamw 113*da6c28aaSamw xfidp = (xattr_fid_t *)fidp; 114*da6c28aaSamw orig_len = fidp->fid_len; 115*da6c28aaSamw fidp->fid_len = sizeof (xfidp->parent_fid); 116*da6c28aaSamw 117*da6c28aaSamw error = VOP_FID(pvp, fidp, ct); 118*da6c28aaSamw if (error) { 119*da6c28aaSamw fidp->fid_len = orig_len; 120*da6c28aaSamw return (error); 121*da6c28aaSamw } 122*da6c28aaSamw 123*da6c28aaSamw xfidp->parent_len = fidp->fid_len; 124*da6c28aaSamw fidp->fid_len = XATTR_FIDSZ; 125*da6c28aaSamw xfidp->dir_offset = gfs_file_inode(vp); 126*da6c28aaSamw 127*da6c28aaSamw return (0); 128*da6c28aaSamw } 129*da6c28aaSamw 130*da6c28aaSamw /* ARGSUSED */ 131*da6c28aaSamw static int 132*da6c28aaSamw xattr_fill_nvlist(vnode_t *vp, xattr_view_t xattr_view, nvlist_t *nvlp, 133*da6c28aaSamw cred_t *cr, caller_context_t *ct) 134*da6c28aaSamw { 135*da6c28aaSamw int error; 136*da6c28aaSamw f_attr_t attr; 137*da6c28aaSamw uint64_t fsid; 138*da6c28aaSamw dev_t mdev; 139*da6c28aaSamw xvattr_t xvattr; 140*da6c28aaSamw xoptattr_t *xoap; /* Pointer to optional attributes */ 141*da6c28aaSamw vnode_t *ppvp; 142*da6c28aaSamw const char *domain; 143*da6c28aaSamw uint32_t rid; 144*da6c28aaSamw 145*da6c28aaSamw xva_init(&xvattr); 146*da6c28aaSamw 147*da6c28aaSamw if ((xoap = xva_getxoptattr(&xvattr)) == NULL) 148*da6c28aaSamw return (EINVAL); 149*da6c28aaSamw 150*da6c28aaSamw /* 151*da6c28aaSamw * For detecting ephemeral uid/gid 152*da6c28aaSamw */ 153*da6c28aaSamw xvattr.xva_vattr.va_mask |= (AT_UID|AT_GID); 154*da6c28aaSamw 155*da6c28aaSamw /* 156*da6c28aaSamw * We need to access the real fs object. 157*da6c28aaSamw * vp points to a GFS file; ppvp points to the real object. 158*da6c28aaSamw */ 159*da6c28aaSamw ppvp = gfs_file_parent(gfs_file_parent(vp)); 160*da6c28aaSamw 161*da6c28aaSamw /* 162*da6c28aaSamw * Iterate through the attrs associated with this view 163*da6c28aaSamw */ 164*da6c28aaSamw 165*da6c28aaSamw for (attr = 0; attr < F_ATTR_ALL; attr++) { 166*da6c28aaSamw if (xattr_view != attr_to_xattr_view(attr)) { 167*da6c28aaSamw continue; 168*da6c28aaSamw } 169*da6c28aaSamw 170*da6c28aaSamw switch (attr) { 171*da6c28aaSamw case F_SYSTEM: 172*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_SYSTEM); 173*da6c28aaSamw break; 174*da6c28aaSamw case F_READONLY: 175*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_READONLY); 176*da6c28aaSamw break; 177*da6c28aaSamw case F_HIDDEN: 178*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_HIDDEN); 179*da6c28aaSamw break; 180*da6c28aaSamw case F_ARCHIVE: 181*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_ARCHIVE); 182*da6c28aaSamw break; 183*da6c28aaSamw case F_IMMUTABLE: 184*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_IMMUTABLE); 185*da6c28aaSamw break; 186*da6c28aaSamw case F_APPENDONLY: 187*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_APPENDONLY); 188*da6c28aaSamw break; 189*da6c28aaSamw case F_NOUNLINK: 190*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_NOUNLINK); 191*da6c28aaSamw break; 192*da6c28aaSamw case F_OPAQUE: 193*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_OPAQUE); 194*da6c28aaSamw break; 195*da6c28aaSamw case F_NODUMP: 196*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_NODUMP); 197*da6c28aaSamw break; 198*da6c28aaSamw case F_AV_QUARANTINED: 199*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED); 200*da6c28aaSamw break; 201*da6c28aaSamw case F_AV_MODIFIED: 202*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED); 203*da6c28aaSamw break; 204*da6c28aaSamw case F_AV_SCANSTAMP: 205*da6c28aaSamw if (ppvp->v_type == VREG) 206*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP); 207*da6c28aaSamw break; 208*da6c28aaSamw case F_CRTIME: 209*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_CREATETIME); 210*da6c28aaSamw break; 211*da6c28aaSamw case F_FSID: 212*da6c28aaSamw fsid = (((uint64_t)vp->v_vfsp->vfs_fsid.val[0] << 32) | 213*da6c28aaSamw (uint64_t)(vp->v_vfsp->vfs_fsid.val[1] & 214*da6c28aaSamw 0xffffffff)); 215*da6c28aaSamw VERIFY(nvlist_add_uint64(nvlp, attr_to_name(attr), 216*da6c28aaSamw fsid) == 0); 217*da6c28aaSamw break; 218*da6c28aaSamw case F_MDEV: 219*da6c28aaSamw mdev = ((int16_t)vp->v_vfsp->vfs_dev); 220*da6c28aaSamw VERIFY(nvlist_add_uint16(nvlp, attr_to_name(attr), 221*da6c28aaSamw mdev) == 0); 222*da6c28aaSamw break; 223*da6c28aaSamw default: 224*da6c28aaSamw break; 225*da6c28aaSamw } 226*da6c28aaSamw } 227*da6c28aaSamw 228*da6c28aaSamw error = VOP_GETATTR(ppvp, &xvattr.xva_vattr, 0, cr, ct); 229*da6c28aaSamw if (error) 230*da6c28aaSamw return (error); 231*da6c28aaSamw 232*da6c28aaSamw /* 233*da6c28aaSamw * Process all the optional attributes together here. Notice that 234*da6c28aaSamw * xoap was set when the optional attribute bits were set above. 235*da6c28aaSamw */ 236*da6c28aaSamw if ((xvattr.xva_vattr.va_mask & AT_XVATTR) && xoap) { 237*da6c28aaSamw if (XVA_ISSET_RTN(&xvattr, XAT_READONLY)) { 238*da6c28aaSamw VERIFY(nvlist_add_boolean_value(nvlp, 239*da6c28aaSamw attr_to_name(F_READONLY), 240*da6c28aaSamw xoap->xoa_readonly) == 0); 241*da6c28aaSamw } 242*da6c28aaSamw if (XVA_ISSET_RTN(&xvattr, XAT_HIDDEN)) { 243*da6c28aaSamw VERIFY(nvlist_add_boolean_value(nvlp, 244*da6c28aaSamw attr_to_name(F_HIDDEN), 245*da6c28aaSamw xoap->xoa_hidden) == 0); 246*da6c28aaSamw } 247*da6c28aaSamw if (XVA_ISSET_RTN(&xvattr, XAT_SYSTEM)) { 248*da6c28aaSamw VERIFY(nvlist_add_boolean_value(nvlp, 249*da6c28aaSamw attr_to_name(F_SYSTEM), 250*da6c28aaSamw xoap->xoa_system) == 0); 251*da6c28aaSamw } 252*da6c28aaSamw if (XVA_ISSET_RTN(&xvattr, XAT_ARCHIVE)) { 253*da6c28aaSamw VERIFY(nvlist_add_boolean_value(nvlp, 254*da6c28aaSamw attr_to_name(F_ARCHIVE), 255*da6c28aaSamw xoap->xoa_archive) == 0); 256*da6c28aaSamw } 257*da6c28aaSamw if (XVA_ISSET_RTN(&xvattr, XAT_IMMUTABLE)) { 258*da6c28aaSamw VERIFY(nvlist_add_boolean_value(nvlp, 259*da6c28aaSamw attr_to_name(F_IMMUTABLE), 260*da6c28aaSamw xoap->xoa_immutable) == 0); 261*da6c28aaSamw } 262*da6c28aaSamw if (XVA_ISSET_RTN(&xvattr, XAT_NOUNLINK)) { 263*da6c28aaSamw VERIFY(nvlist_add_boolean_value(nvlp, 264*da6c28aaSamw attr_to_name(F_NOUNLINK), 265*da6c28aaSamw xoap->xoa_nounlink) == 0); 266*da6c28aaSamw } 267*da6c28aaSamw if (XVA_ISSET_RTN(&xvattr, XAT_APPENDONLY)) { 268*da6c28aaSamw VERIFY(nvlist_add_boolean_value(nvlp, 269*da6c28aaSamw attr_to_name(F_APPENDONLY), 270*da6c28aaSamw xoap->xoa_appendonly) == 0); 271*da6c28aaSamw } 272*da6c28aaSamw if (XVA_ISSET_RTN(&xvattr, XAT_NODUMP)) { 273*da6c28aaSamw VERIFY(nvlist_add_boolean_value(nvlp, 274*da6c28aaSamw attr_to_name(F_NODUMP), 275*da6c28aaSamw xoap->xoa_nodump) == 0); 276*da6c28aaSamw } 277*da6c28aaSamw if (XVA_ISSET_RTN(&xvattr, XAT_OPAQUE)) { 278*da6c28aaSamw VERIFY(nvlist_add_boolean_value(nvlp, 279*da6c28aaSamw attr_to_name(F_OPAQUE), 280*da6c28aaSamw xoap->xoa_opaque) == 0); 281*da6c28aaSamw } 282*da6c28aaSamw if (XVA_ISSET_RTN(&xvattr, XAT_AV_QUARANTINED)) { 283*da6c28aaSamw VERIFY(nvlist_add_boolean_value(nvlp, 284*da6c28aaSamw attr_to_name(F_AV_QUARANTINED), 285*da6c28aaSamw xoap->xoa_av_quarantined) == 0); 286*da6c28aaSamw } 287*da6c28aaSamw if (XVA_ISSET_RTN(&xvattr, XAT_AV_MODIFIED)) { 288*da6c28aaSamw VERIFY(nvlist_add_boolean_value(nvlp, 289*da6c28aaSamw attr_to_name(F_AV_MODIFIED), 290*da6c28aaSamw xoap->xoa_av_modified) == 0); 291*da6c28aaSamw } 292*da6c28aaSamw if (XVA_ISSET_RTN(&xvattr, XAT_AV_SCANSTAMP)) { 293*da6c28aaSamw VERIFY(nvlist_add_uint8_array(nvlp, 294*da6c28aaSamw attr_to_name(F_AV_SCANSTAMP), 295*da6c28aaSamw xoap->xoa_av_scanstamp, 296*da6c28aaSamw sizeof (xoap->xoa_av_scanstamp)) == 0); 297*da6c28aaSamw } 298*da6c28aaSamw if (XVA_ISSET_RTN(&xvattr, XAT_CREATETIME)) { 299*da6c28aaSamw VERIFY(nvlist_add_uint64_array(nvlp, 300*da6c28aaSamw attr_to_name(F_CRTIME), 301*da6c28aaSamw (uint64_t *)&(xoap->xoa_createtime), 302*da6c28aaSamw sizeof (xoap->xoa_createtime) / 303*da6c28aaSamw sizeof (uint64_t)) == 0); 304*da6c28aaSamw } 305*da6c28aaSamw } 306*da6c28aaSamw /* 307*da6c28aaSamw * Check for optional ownersid/groupsid 308*da6c28aaSamw */ 309*da6c28aaSamw 310*da6c28aaSamw if (xvattr.xva_vattr.va_uid > MAXUID) { 311*da6c28aaSamw nvlist_t *nvl_sid; 312*da6c28aaSamw 313*da6c28aaSamw if (nvlist_alloc(&nvl_sid, NV_UNIQUE_NAME, KM_SLEEP)) 314*da6c28aaSamw return (ENOMEM); 315*da6c28aaSamw 316*da6c28aaSamw if (kidmap_getsidbyuid(xvattr.xva_vattr.va_uid, 317*da6c28aaSamw &domain, &rid) == 0) { 318*da6c28aaSamw VERIFY(nvlist_add_string(nvl_sid, 319*da6c28aaSamw SID_DOMAIN, domain) == 0); 320*da6c28aaSamw VERIFY(nvlist_add_uint32(nvl_sid, SID_RID, rid) == 0); 321*da6c28aaSamw VERIFY(nvlist_add_nvlist(nvlp, attr_to_name(F_OWNERSID), 322*da6c28aaSamw nvl_sid) == 0); 323*da6c28aaSamw } 324*da6c28aaSamw nvlist_free(nvl_sid); 325*da6c28aaSamw } 326*da6c28aaSamw if (xvattr.xva_vattr.va_gid > MAXUID) { 327*da6c28aaSamw nvlist_t *nvl_sid; 328*da6c28aaSamw 329*da6c28aaSamw if (nvlist_alloc(&nvl_sid, NV_UNIQUE_NAME, KM_SLEEP)) 330*da6c28aaSamw return (ENOMEM); 331*da6c28aaSamw 332*da6c28aaSamw if (kidmap_getsidbygid(xvattr.xva_vattr.va_gid, 333*da6c28aaSamw &domain, &rid) == 0) { 334*da6c28aaSamw VERIFY(nvlist_add_string(nvl_sid, 335*da6c28aaSamw SID_DOMAIN, domain) == 0); 336*da6c28aaSamw VERIFY(nvlist_add_uint32(nvl_sid, SID_RID, rid) == 0); 337*da6c28aaSamw VERIFY(nvlist_add_nvlist(nvlp, attr_to_name(F_GROUPSID), 338*da6c28aaSamw nvl_sid) == 0); 339*da6c28aaSamw } 340*da6c28aaSamw nvlist_free(nvl_sid); 341*da6c28aaSamw } 342*da6c28aaSamw 343*da6c28aaSamw return (0); 344*da6c28aaSamw } 345*da6c28aaSamw 346*da6c28aaSamw /* 347*da6c28aaSamw * The size of a sysattr file is the size of the nvlist that will be 348*da6c28aaSamw * returned by xattr_file_read(). A call to xattr_file_write() could 349*da6c28aaSamw * change the size of that nvlist. That size is not stored persistently 350*da6c28aaSamw * so xattr_fill_nvlist() calls VOP_GETATTR so that it can be calculated. 351*da6c28aaSamw */ 352*da6c28aaSamw static int 353*da6c28aaSamw xattr_file_size(vnode_t *vp, xattr_view_t xattr_view, size_t *size, 354*da6c28aaSamw cred_t *cr, caller_context_t *ct) 355*da6c28aaSamw { 356*da6c28aaSamw nvlist_t *nvl; 357*da6c28aaSamw 358*da6c28aaSamw if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP)) { 359*da6c28aaSamw return (ENOMEM); 360*da6c28aaSamw } 361*da6c28aaSamw 362*da6c28aaSamw if (xattr_fill_nvlist(vp, xattr_view, nvl, cr, ct)) { 363*da6c28aaSamw nvlist_free(nvl); 364*da6c28aaSamw return (EFAULT); 365*da6c28aaSamw } 366*da6c28aaSamw 367*da6c28aaSamw VERIFY(nvlist_size(nvl, size, NV_ENCODE_XDR) == 0); 368*da6c28aaSamw nvlist_free(nvl); 369*da6c28aaSamw return (0); 370*da6c28aaSamw } 371*da6c28aaSamw 372*da6c28aaSamw /* ARGSUSED */ 373*da6c28aaSamw static int 374*da6c28aaSamw xattr_file_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, 375*da6c28aaSamw caller_context_t *ct) 376*da6c28aaSamw { 377*da6c28aaSamw xattr_file_t *np = vp->v_data; 378*da6c28aaSamw timestruc_t now; 379*da6c28aaSamw size_t size; 380*da6c28aaSamw int error; 381*da6c28aaSamw vnode_t *pvp; 382*da6c28aaSamw vattr_t pvattr; 383*da6c28aaSamw 384*da6c28aaSamw vap->va_type = VREG; 385*da6c28aaSamw vap->va_mode = MAKEIMODE(vap->va_type, 386*da6c28aaSamw (np->xattr_view == XATTR_VIEW_READONLY ? 0444 : 0644)); 387*da6c28aaSamw vap->va_nodeid = gfs_file_inode(vp); 388*da6c28aaSamw vap->va_nlink = 1; 389*da6c28aaSamw pvp = gfs_file_parent(vp); 390*da6c28aaSamw (void) memset(&pvattr, 0, sizeof (pvattr)); 391*da6c28aaSamw pvattr.va_mask = AT_CTIME|AT_MTIME; 392*da6c28aaSamw error = VOP_GETATTR(pvp, &pvattr, flags, cr, ct); 393*da6c28aaSamw if (error) { 394*da6c28aaSamw return (error); 395*da6c28aaSamw } 396*da6c28aaSamw vap->va_ctime = pvattr.va_ctime; 397*da6c28aaSamw vap->va_mtime = pvattr.va_mtime; 398*da6c28aaSamw gethrestime(&now); 399*da6c28aaSamw vap->va_atime = now; 400*da6c28aaSamw vap->va_uid = 0; 401*da6c28aaSamw vap->va_gid = 0; 402*da6c28aaSamw vap->va_rdev = 0; 403*da6c28aaSamw vap->va_blksize = DEV_BSIZE; 404*da6c28aaSamw vap->va_seq = 0; 405*da6c28aaSamw vap->va_fsid = vp->v_vfsp->vfs_dev; 406*da6c28aaSamw error = xattr_file_size(vp, np->xattr_view, &size, cr, ct); 407*da6c28aaSamw vap->va_size = size; 408*da6c28aaSamw vap->va_nblocks = howmany(vap->va_size, vap->va_blksize); 409*da6c28aaSamw return (error); 410*da6c28aaSamw } 411*da6c28aaSamw 412*da6c28aaSamw /* ARGSUSED */ 413*da6c28aaSamw static int 414*da6c28aaSamw xattr_file_read(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr, 415*da6c28aaSamw caller_context_t *ct) 416*da6c28aaSamw { 417*da6c28aaSamw xattr_file_t *np = vp->v_data; 418*da6c28aaSamw xattr_view_t xattr_view = np->xattr_view; 419*da6c28aaSamw char *buf; 420*da6c28aaSamw size_t filesize; 421*da6c28aaSamw nvlist_t *nvl; 422*da6c28aaSamw int error; 423*da6c28aaSamw 424*da6c28aaSamw /* 425*da6c28aaSamw * Validate file offset and fasttrack empty reads 426*da6c28aaSamw */ 427*da6c28aaSamw if (uiop->uio_loffset < (offset_t)0) 428*da6c28aaSamw return (EINVAL); 429*da6c28aaSamw 430*da6c28aaSamw if (uiop->uio_resid == 0) 431*da6c28aaSamw return (0); 432*da6c28aaSamw 433*da6c28aaSamw if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP)) 434*da6c28aaSamw return (ENOMEM); 435*da6c28aaSamw 436*da6c28aaSamw if (xattr_fill_nvlist(vp, xattr_view, nvl, cr, ct)) { 437*da6c28aaSamw nvlist_free(nvl); 438*da6c28aaSamw return (EFAULT); 439*da6c28aaSamw } 440*da6c28aaSamw 441*da6c28aaSamw VERIFY(nvlist_size(nvl, &filesize, NV_ENCODE_XDR) == 0); 442*da6c28aaSamw 443*da6c28aaSamw if (uiop->uio_loffset >= filesize) { 444*da6c28aaSamw nvlist_free(nvl); 445*da6c28aaSamw return (0); 446*da6c28aaSamw } 447*da6c28aaSamw 448*da6c28aaSamw buf = kmem_alloc(filesize, KM_SLEEP); 449*da6c28aaSamw VERIFY(nvlist_pack(nvl, &buf, &filesize, NV_ENCODE_XDR, 450*da6c28aaSamw KM_SLEEP) == 0); 451*da6c28aaSamw 452*da6c28aaSamw error = uiomove((caddr_t)buf, filesize, UIO_READ, uiop); 453*da6c28aaSamw kmem_free(buf, filesize); 454*da6c28aaSamw nvlist_free(nvl); 455*da6c28aaSamw return (error); 456*da6c28aaSamw } 457*da6c28aaSamw 458*da6c28aaSamw /* ARGSUSED */ 459*da6c28aaSamw static int 460*da6c28aaSamw xattr_file_write(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr, 461*da6c28aaSamw caller_context_t *ct) 462*da6c28aaSamw { 463*da6c28aaSamw int error = 0; 464*da6c28aaSamw char *buf; 465*da6c28aaSamw char *domain; 466*da6c28aaSamw uint32_t rid; 467*da6c28aaSamw ssize_t size = uiop->uio_resid; 468*da6c28aaSamw nvlist_t *nvp; 469*da6c28aaSamw nvpair_t *pair = NULL; 470*da6c28aaSamw vnode_t *ppvp; 471*da6c28aaSamw xvattr_t xvattr; 472*da6c28aaSamw xoptattr_t *xoap = NULL; /* Pointer to optional attributes */ 473*da6c28aaSamw 474*da6c28aaSamw /* 475*da6c28aaSamw * Validate file offset and size. 476*da6c28aaSamw */ 477*da6c28aaSamw if (uiop->uio_loffset < (offset_t)0) 478*da6c28aaSamw return (EINVAL); 479*da6c28aaSamw 480*da6c28aaSamw if (size == 0) 481*da6c28aaSamw return (EINVAL); 482*da6c28aaSamw 483*da6c28aaSamw xva_init(&xvattr); 484*da6c28aaSamw 485*da6c28aaSamw if ((xoap = xva_getxoptattr(&xvattr)) == NULL) { 486*da6c28aaSamw return (EINVAL); 487*da6c28aaSamw } 488*da6c28aaSamw 489*da6c28aaSamw /* 490*da6c28aaSamw * Copy and unpack the nvlist 491*da6c28aaSamw */ 492*da6c28aaSamw buf = kmem_alloc(size, KM_SLEEP); 493*da6c28aaSamw if (uiomove((caddr_t)buf, size, UIO_WRITE, uiop)) { 494*da6c28aaSamw return (EFAULT); 495*da6c28aaSamw } 496*da6c28aaSamw 497*da6c28aaSamw if (nvlist_unpack(buf, size, &nvp, KM_SLEEP) != 0) { 498*da6c28aaSamw kmem_free(buf, size); 499*da6c28aaSamw uiop->uio_resid = size; 500*da6c28aaSamw return (EINVAL); 501*da6c28aaSamw } 502*da6c28aaSamw kmem_free(buf, size); 503*da6c28aaSamw 504*da6c28aaSamw /* 505*da6c28aaSamw * Fasttrack empty writes (nvlist with no nvpairs) 506*da6c28aaSamw */ 507*da6c28aaSamw if (nvlist_next_nvpair(nvp, NULL) == 0) 508*da6c28aaSamw return (0); 509*da6c28aaSamw 510*da6c28aaSamw ppvp = gfs_file_parent(gfs_file_parent(vp)); 511*da6c28aaSamw 512*da6c28aaSamw while (pair = nvlist_next_nvpair(nvp, pair)) { 513*da6c28aaSamw data_type_t type; 514*da6c28aaSamw f_attr_t attr; 515*da6c28aaSamw boolean_t value; 516*da6c28aaSamw uint64_t *time, *times; 517*da6c28aaSamw uint_t elem, nelems; 518*da6c28aaSamw nvlist_t *nvp_sid; 519*da6c28aaSamw uint8_t *scanstamp; 520*da6c28aaSamw 521*da6c28aaSamw /* 522*da6c28aaSamw * Validate the name and type of each attribute. 523*da6c28aaSamw * Log any unknown names and continue. This will 524*da6c28aaSamw * help if additional attributes are added later. 525*da6c28aaSamw */ 526*da6c28aaSamw type = nvpair_type(pair); 527*da6c28aaSamw if ((attr = name_to_attr(nvpair_name(pair))) == F_ATTR_INVAL) { 528*da6c28aaSamw cmn_err(CE_WARN, "Unknown attribute %s", 529*da6c28aaSamw nvpair_name(pair)); 530*da6c28aaSamw continue; 531*da6c28aaSamw } 532*da6c28aaSamw 533*da6c28aaSamw /* 534*da6c28aaSamw * Verify nvlist type matches required type and view is OK 535*da6c28aaSamw */ 536*da6c28aaSamw 537*da6c28aaSamw if (type != attr_to_data_type(attr) || 538*da6c28aaSamw (attr_to_xattr_view(attr) == XATTR_VIEW_READONLY)) { 539*da6c28aaSamw nvlist_free(nvp); 540*da6c28aaSamw return (EINVAL); 541*da6c28aaSamw } 542*da6c28aaSamw 543*da6c28aaSamw /* 544*da6c28aaSamw * For OWNERSID/GROUPSID make sure the target 545*da6c28aaSamw * file system support ephemeral ID's 546*da6c28aaSamw */ 547*da6c28aaSamw if ((attr == F_OWNERSID || attr == F_GROUPSID) && 548*da6c28aaSamw (!(vp->v_vfsp->vfs_flag & VFS_XID))) { 549*da6c28aaSamw nvlist_free(nvp); 550*da6c28aaSamw return (EINVAL); 551*da6c28aaSamw } 552*da6c28aaSamw 553*da6c28aaSamw /* 554*da6c28aaSamw * Retrieve data from nvpair 555*da6c28aaSamw */ 556*da6c28aaSamw switch (type) { 557*da6c28aaSamw case DATA_TYPE_BOOLEAN_VALUE: 558*da6c28aaSamw if (nvpair_value_boolean_value(pair, &value)) { 559*da6c28aaSamw nvlist_free(nvp); 560*da6c28aaSamw return (EINVAL); 561*da6c28aaSamw } 562*da6c28aaSamw break; 563*da6c28aaSamw case DATA_TYPE_UINT64_ARRAY: 564*da6c28aaSamw if (nvpair_value_uint64_array(pair, ×, &nelems)) { 565*da6c28aaSamw nvlist_free(nvp); 566*da6c28aaSamw return (EINVAL); 567*da6c28aaSamw } 568*da6c28aaSamw break; 569*da6c28aaSamw case DATA_TYPE_NVLIST: 570*da6c28aaSamw if (nvpair_value_nvlist(pair, &nvp_sid)) { 571*da6c28aaSamw nvlist_free(nvp); 572*da6c28aaSamw return (EINVAL); 573*da6c28aaSamw } 574*da6c28aaSamw break; 575*da6c28aaSamw case DATA_TYPE_UINT8_ARRAY: 576*da6c28aaSamw if (nvpair_value_uint8_array(pair, 577*da6c28aaSamw &scanstamp, &nelems)) { 578*da6c28aaSamw nvlist_free(nvp); 579*da6c28aaSamw return (EINVAL); 580*da6c28aaSamw } 581*da6c28aaSamw break; 582*da6c28aaSamw default: 583*da6c28aaSamw nvlist_free(nvp); 584*da6c28aaSamw return (EINVAL); 585*da6c28aaSamw } 586*da6c28aaSamw 587*da6c28aaSamw switch (attr) { 588*da6c28aaSamw /* 589*da6c28aaSamw * If we have several similar optional attributes to 590*da6c28aaSamw * process then we should do it all together here so that 591*da6c28aaSamw * xoap and the requested bitmap can be set in one place. 592*da6c28aaSamw */ 593*da6c28aaSamw case F_READONLY: 594*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_READONLY); 595*da6c28aaSamw xoap->xoa_readonly = value; 596*da6c28aaSamw break; 597*da6c28aaSamw case F_HIDDEN: 598*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_HIDDEN); 599*da6c28aaSamw xoap->xoa_hidden = value; 600*da6c28aaSamw break; 601*da6c28aaSamw case F_SYSTEM: 602*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_SYSTEM); 603*da6c28aaSamw xoap->xoa_system = value; 604*da6c28aaSamw break; 605*da6c28aaSamw case F_ARCHIVE: 606*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_ARCHIVE); 607*da6c28aaSamw xoap->xoa_archive = value; 608*da6c28aaSamw break; 609*da6c28aaSamw case F_IMMUTABLE: 610*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_IMMUTABLE); 611*da6c28aaSamw xoap->xoa_immutable = value; 612*da6c28aaSamw break; 613*da6c28aaSamw case F_NOUNLINK: 614*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_NOUNLINK); 615*da6c28aaSamw xoap->xoa_nounlink = value; 616*da6c28aaSamw break; 617*da6c28aaSamw case F_APPENDONLY: 618*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_APPENDONLY); 619*da6c28aaSamw xoap->xoa_appendonly = value; 620*da6c28aaSamw break; 621*da6c28aaSamw case F_NODUMP: 622*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_NODUMP); 623*da6c28aaSamw xoap->xoa_nodump = value; 624*da6c28aaSamw break; 625*da6c28aaSamw case F_AV_QUARANTINED: 626*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED); 627*da6c28aaSamw xoap->xoa_av_quarantined = value; 628*da6c28aaSamw break; 629*da6c28aaSamw case F_AV_MODIFIED: 630*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED); 631*da6c28aaSamw xoap->xoa_av_modified = value; 632*da6c28aaSamw break; 633*da6c28aaSamw case F_CRTIME: 634*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_CREATETIME); 635*da6c28aaSamw time = (uint64_t *)&(xoap->xoa_createtime); 636*da6c28aaSamw for (elem = 0; elem < nelems; elem++) 637*da6c28aaSamw *time++ = times[elem]; 638*da6c28aaSamw break; 639*da6c28aaSamw case F_OWNERSID: 640*da6c28aaSamw case F_GROUPSID: 641*da6c28aaSamw if (nvlist_lookup_string(nvp_sid, SID_DOMAIN, 642*da6c28aaSamw &domain) || nvlist_lookup_uint32(nvp_sid, SID_RID, 643*da6c28aaSamw &rid)) { 644*da6c28aaSamw nvlist_free(nvp); 645*da6c28aaSamw return (EINVAL); 646*da6c28aaSamw } 647*da6c28aaSamw 648*da6c28aaSamw /* 649*da6c28aaSamw * Now map domain+rid to ephemeral id's 650*da6c28aaSamw * 651*da6c28aaSamw * If mapping fails, then the uid/gid will 652*da6c28aaSamw * be set to UID_NOBODY by Winchester. 653*da6c28aaSamw */ 654*da6c28aaSamw 655*da6c28aaSamw if (attr == F_OWNERSID) { 656*da6c28aaSamw (void) kidmap_getuidbysid(domain, rid, 657*da6c28aaSamw &xvattr.xva_vattr.va_uid); 658*da6c28aaSamw xvattr.xva_vattr.va_mask |= AT_UID; 659*da6c28aaSamw } else { 660*da6c28aaSamw (void) kidmap_getgidbysid(domain, rid, 661*da6c28aaSamw &xvattr.xva_vattr.va_gid); 662*da6c28aaSamw xvattr.xva_vattr.va_mask |= AT_GID; 663*da6c28aaSamw } 664*da6c28aaSamw break; 665*da6c28aaSamw case F_AV_SCANSTAMP: 666*da6c28aaSamw if (ppvp->v_type == VREG) { 667*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP); 668*da6c28aaSamw (void) memcpy(xoap->xoa_av_scanstamp, 669*da6c28aaSamw scanstamp, nelems); 670*da6c28aaSamw } else { 671*da6c28aaSamw nvlist_free(nvp); 672*da6c28aaSamw return (EINVAL); 673*da6c28aaSamw } 674*da6c28aaSamw break; 675*da6c28aaSamw default: 676*da6c28aaSamw break; 677*da6c28aaSamw } 678*da6c28aaSamw } 679*da6c28aaSamw 680*da6c28aaSamw ppvp = gfs_file_parent(gfs_file_parent(vp)); 681*da6c28aaSamw error = VOP_SETATTR(ppvp, &xvattr.xva_vattr, 0, cr, ct); 682*da6c28aaSamw if (error) 683*da6c28aaSamw uiop->uio_resid = size; 684*da6c28aaSamw 685*da6c28aaSamw nvlist_free(nvp); 686*da6c28aaSamw return (error); 687*da6c28aaSamw } 688*da6c28aaSamw 689*da6c28aaSamw static int 690*da6c28aaSamw xattr_file_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr, 691*da6c28aaSamw caller_context_t *ct) 692*da6c28aaSamw { 693*da6c28aaSamw switch (cmd) { 694*da6c28aaSamw case _PC_XATTR_EXISTS: 695*da6c28aaSamw case _PC_SATTR_ENABLED: 696*da6c28aaSamw case _PC_SATTR_EXISTS: 697*da6c28aaSamw *valp = 0; 698*da6c28aaSamw return (0); 699*da6c28aaSamw default: 700*da6c28aaSamw return (fs_pathconf(vp, cmd, valp, cr, ct)); 701*da6c28aaSamw } 702*da6c28aaSamw } 703*da6c28aaSamw 704*da6c28aaSamw vnodeops_t *xattr_file_ops; 705*da6c28aaSamw 706*da6c28aaSamw static const fs_operation_def_t xattr_file_tops[] = { 707*da6c28aaSamw { VOPNAME_OPEN, { .vop_open = xattr_file_open } }, 708*da6c28aaSamw { VOPNAME_CLOSE, { .vop_close = xattr_file_close } }, 709*da6c28aaSamw { VOPNAME_READ, { .vop_read = xattr_file_read } }, 710*da6c28aaSamw { VOPNAME_WRITE, { .vop_write = xattr_file_write } }, 711*da6c28aaSamw { VOPNAME_IOCTL, { .error = fs_ioctl } }, 712*da6c28aaSamw { VOPNAME_GETATTR, { .vop_getattr = xattr_file_getattr } }, 713*da6c28aaSamw { VOPNAME_ACCESS, { .vop_access = xattr_file_access } }, 714*da6c28aaSamw { VOPNAME_READDIR, { .error = fs_notdir } }, 715*da6c28aaSamw { VOPNAME_SEEK, { .vop_seek = fs_seek } }, 716*da6c28aaSamw { VOPNAME_INACTIVE, { .vop_inactive = gfs_vop_inactive } }, 717*da6c28aaSamw { VOPNAME_FID, { .vop_fid = xattr_common_fid } }, 718*da6c28aaSamw { VOPNAME_PATHCONF, { .vop_pathconf = xattr_file_pathconf } }, 719*da6c28aaSamw { VOPNAME_PUTPAGE, { .error = fs_putpage } }, 720*da6c28aaSamw { VOPNAME_FSYNC, { .error = fs_fsync } }, 721*da6c28aaSamw { NULL } 722*da6c28aaSamw }; 723*da6c28aaSamw 724*da6c28aaSamw vnode_t * 725*da6c28aaSamw xattr_mkfile(vnode_t *pvp, xattr_view_t xattr_view) 726*da6c28aaSamw { 727*da6c28aaSamw vnode_t *vp; 728*da6c28aaSamw xattr_file_t *np; 729*da6c28aaSamw 730*da6c28aaSamw vp = gfs_file_create(sizeof (xattr_file_t), pvp, xattr_file_ops); 731*da6c28aaSamw np = vp->v_data; 732*da6c28aaSamw np->xattr_view = xattr_view; 733*da6c28aaSamw vp->v_flag |= V_SYSATTR; 734*da6c28aaSamw return (vp); 735*da6c28aaSamw } 736*da6c28aaSamw 737*da6c28aaSamw vnode_t * 738*da6c28aaSamw xattr_mkfile_ro(vnode_t *pvp) 739*da6c28aaSamw { 740*da6c28aaSamw return (xattr_mkfile(pvp, XATTR_VIEW_READONLY)); 741*da6c28aaSamw } 742*da6c28aaSamw 743*da6c28aaSamw vnode_t * 744*da6c28aaSamw xattr_mkfile_rw(vnode_t *pvp) 745*da6c28aaSamw { 746*da6c28aaSamw return (xattr_mkfile(pvp, XATTR_VIEW_READWRITE)); 747*da6c28aaSamw } 748*da6c28aaSamw 749*da6c28aaSamw vnodeops_t *xattr_dir_ops; 750*da6c28aaSamw 751*da6c28aaSamw static gfs_dirent_t xattr_dirents[] = { 752*da6c28aaSamw { VIEW_READONLY, xattr_mkfile_ro, GFS_CACHE_VNODE, }, 753*da6c28aaSamw { VIEW_READWRITE, xattr_mkfile_rw, GFS_CACHE_VNODE, }, 754*da6c28aaSamw { NULL }, 755*da6c28aaSamw }; 756*da6c28aaSamw 757*da6c28aaSamw #define XATTRDIR_NENTS ((sizeof (xattr_dirents) / sizeof (gfs_dirent_t)) - 1) 758*da6c28aaSamw 759*da6c28aaSamw static int 760*da6c28aaSamw is_sattr_name(char *s) 761*da6c28aaSamw { 762*da6c28aaSamw int i; 763*da6c28aaSamw 764*da6c28aaSamw for (i = 0; i < XATTRDIR_NENTS; ++i) { 765*da6c28aaSamw if (strcmp(s, xattr_dirents[i].gfse_name) == 0) { 766*da6c28aaSamw return (1); 767*da6c28aaSamw } 768*da6c28aaSamw } 769*da6c28aaSamw return (0); 770*da6c28aaSamw } 771*da6c28aaSamw 772*da6c28aaSamw static int 773*da6c28aaSamw xattr_copy(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, 774*da6c28aaSamw cred_t *cr, caller_context_t *ct) 775*da6c28aaSamw { 776*da6c28aaSamw xvattr_t xvattr; 777*da6c28aaSamw vnode_t *pdvp; 778*da6c28aaSamw int error; 779*da6c28aaSamw 780*da6c28aaSamw /* 781*da6c28aaSamw * Only copy system attrs if the views are the same 782*da6c28aaSamw */ 783*da6c28aaSamw if (strcmp(snm, tnm) != 0) 784*da6c28aaSamw return (EINVAL); 785*da6c28aaSamw 786*da6c28aaSamw xva_init(&xvattr); 787*da6c28aaSamw 788*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_SYSTEM); 789*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_READONLY); 790*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_HIDDEN); 791*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_ARCHIVE); 792*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_APPENDONLY); 793*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_NOUNLINK); 794*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_IMMUTABLE); 795*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_NODUMP); 796*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED); 797*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED); 798*da6c28aaSamw XVA_SET_REQ(&xvattr, XAT_CREATETIME); 799*da6c28aaSamw 800*da6c28aaSamw pdvp = gfs_file_parent(sdvp); 801*da6c28aaSamw error = VOP_GETATTR(pdvp, &xvattr.xva_vattr, 0, cr, ct); 802*da6c28aaSamw if (error) 803*da6c28aaSamw return (error); 804*da6c28aaSamw 805*da6c28aaSamw pdvp = gfs_file_parent(tdvp); 806*da6c28aaSamw error = VOP_SETATTR(pdvp, &xvattr.xva_vattr, 0, cr, ct); 807*da6c28aaSamw return (error); 808*da6c28aaSamw } 809*da6c28aaSamw 810*da6c28aaSamw static int 811*da6c28aaSamw xattr_dir_realdir(vnode_t *dvp, vnode_t **realdvp, int lookup_flags, 812*da6c28aaSamw cred_t *cr, caller_context_t *ct) 813*da6c28aaSamw { 814*da6c28aaSamw vnode_t *pvp; 815*da6c28aaSamw int error; 816*da6c28aaSamw struct pathname pn; 817*da6c28aaSamw char *startnm = ""; 818*da6c28aaSamw 819*da6c28aaSamw *realdvp = NULL; 820*da6c28aaSamw 821*da6c28aaSamw pvp = gfs_file_parent(dvp); 822*da6c28aaSamw 823*da6c28aaSamw error = pn_get(startnm, UIO_SYSSPACE, &pn); 824*da6c28aaSamw if (error) { 825*da6c28aaSamw VN_RELE(pvp); 826*da6c28aaSamw return (error); 827*da6c28aaSamw } 828*da6c28aaSamw 829*da6c28aaSamw /* 830*da6c28aaSamw * Set the LOOKUP_HAVE_SYSATTR_DIR flag so that we don't get into an 831*da6c28aaSamw * infinite loop with fop_lookup calling back to xattr_dir_lookup. 832*da6c28aaSamw */ 833*da6c28aaSamw lookup_flags |= LOOKUP_HAVE_SYSATTR_DIR; 834*da6c28aaSamw error = VOP_LOOKUP(pvp, startnm, realdvp, &pn, lookup_flags, 835*da6c28aaSamw rootvp, cr, ct, NULL, NULL); 836*da6c28aaSamw pn_free(&pn); 837*da6c28aaSamw 838*da6c28aaSamw return (error); 839*da6c28aaSamw } 840*da6c28aaSamw 841*da6c28aaSamw /* ARGSUSED */ 842*da6c28aaSamw static int 843*da6c28aaSamw xattr_dir_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct) 844*da6c28aaSamw { 845*da6c28aaSamw if (flags & FWRITE) { 846*da6c28aaSamw return (EACCES); 847*da6c28aaSamw } 848*da6c28aaSamw 849*da6c28aaSamw return (0); 850*da6c28aaSamw } 851*da6c28aaSamw 852*da6c28aaSamw /* ARGSUSED */ 853*da6c28aaSamw static int 854*da6c28aaSamw xattr_dir_close(vnode_t *vpp, int flags, int count, offset_t off, cred_t *cr, 855*da6c28aaSamw caller_context_t *ct) 856*da6c28aaSamw { 857*da6c28aaSamw return (0); 858*da6c28aaSamw } 859*da6c28aaSamw 860*da6c28aaSamw /* ARGSUSED */ 861*da6c28aaSamw static int 862*da6c28aaSamw xattr_dir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, 863*da6c28aaSamw caller_context_t *ct) 864*da6c28aaSamw { 865*da6c28aaSamw timestruc_t now; 866*da6c28aaSamw vnode_t *pvp; 867*da6c28aaSamw int error; 868*da6c28aaSamw vattr_t pvattr; 869*da6c28aaSamw 870*da6c28aaSamw error = xattr_dir_realdir(vp, &pvp, LOOKUP_XATTR, cr, ct); 871*da6c28aaSamw if (error == 0) { 872*da6c28aaSamw error = VOP_GETATTR(pvp, vap, 0, cr, ct); 873*da6c28aaSamw VN_RELE(pvp); 874*da6c28aaSamw if (error) { 875*da6c28aaSamw return (error); 876*da6c28aaSamw } 877*da6c28aaSamw vap->va_nlink += XATTRDIR_NENTS; 878*da6c28aaSamw vap->va_size += XATTRDIR_NENTS; 879*da6c28aaSamw return (0); 880*da6c28aaSamw } 881*da6c28aaSamw 882*da6c28aaSamw /* 883*da6c28aaSamw * There is no real xattr directory. Cobble together 884*da6c28aaSamw * an entry using info from the parent object. 885*da6c28aaSamw */ 886*da6c28aaSamw pvp = gfs_file_parent(vp); 887*da6c28aaSamw (void) memset(&pvattr, 0, sizeof (pvattr)); 888*da6c28aaSamw pvattr.va_mask = AT_UID|AT_GID|AT_RDEV|AT_CTIME|AT_MTIME; 889*da6c28aaSamw error = VOP_GETATTR(pvp, &pvattr, 0, cr, ct); 890*da6c28aaSamw if (error) { 891*da6c28aaSamw return (error); 892*da6c28aaSamw } 893*da6c28aaSamw *vap = pvattr; 894*da6c28aaSamw vap->va_type = VDIR; 895*da6c28aaSamw vap->va_mode = MAKEIMODE(vap->va_type, S_ISVTX | 0777); 896*da6c28aaSamw vap->va_fsid = vp->v_vfsp->vfs_dev; 897*da6c28aaSamw vap->va_nodeid = gfs_file_inode(vp); 898*da6c28aaSamw vap->va_nlink = XATTRDIR_NENTS+2; 899*da6c28aaSamw vap->va_size = vap->va_nlink; 900*da6c28aaSamw gethrestime(&now); 901*da6c28aaSamw vap->va_atime = now; 902*da6c28aaSamw vap->va_blksize = 0; 903*da6c28aaSamw vap->va_nblocks = 0; 904*da6c28aaSamw vap->va_seq = 0; 905*da6c28aaSamw return (0); 906*da6c28aaSamw } 907*da6c28aaSamw 908*da6c28aaSamw static int 909*da6c28aaSamw xattr_dir_setattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, 910*da6c28aaSamw caller_context_t *ct) 911*da6c28aaSamw { 912*da6c28aaSamw vnode_t *realvp; 913*da6c28aaSamw int error; 914*da6c28aaSamw 915*da6c28aaSamw /* 916*da6c28aaSamw * If there is a real xattr directory, do the setattr there. 917*da6c28aaSamw * Otherwise, just return success. The GFS directory is transient, 918*da6c28aaSamw * and any setattr changes can disappear anyway. 919*da6c28aaSamw */ 920*da6c28aaSamw error = xattr_dir_realdir(vp, &realvp, LOOKUP_XATTR, cr, ct); 921*da6c28aaSamw if (error == 0) { 922*da6c28aaSamw error = VOP_SETATTR(realvp, vap, flags, cr, ct); 923*da6c28aaSamw VN_RELE(realvp); 924*da6c28aaSamw } 925*da6c28aaSamw if (error == ENOENT) { 926*da6c28aaSamw error = 0; 927*da6c28aaSamw } 928*da6c28aaSamw return (error); 929*da6c28aaSamw } 930*da6c28aaSamw 931*da6c28aaSamw /* ARGSUSED */ 932*da6c28aaSamw static int 933*da6c28aaSamw xattr_dir_access(vnode_t *vp, int mode, int flags, cred_t *cr, 934*da6c28aaSamw caller_context_t *ct) 935*da6c28aaSamw { 936*da6c28aaSamw int error; 937*da6c28aaSamw vnode_t *realvp = NULL; 938*da6c28aaSamw 939*da6c28aaSamw if (mode & VWRITE) { 940*da6c28aaSamw return (EACCES); 941*da6c28aaSamw } 942*da6c28aaSamw 943*da6c28aaSamw error = xattr_dir_realdir(vp, &realvp, LOOKUP_XATTR, cr, ct); 944*da6c28aaSamw 945*da6c28aaSamw if (realvp) 946*da6c28aaSamw VN_RELE(realvp); 947*da6c28aaSamw 948*da6c28aaSamw /* 949*da6c28aaSamw * No real xattr dir isn't an error 950*da6c28aaSamw * an error of EINVAL indicates attributes on attributes 951*da6c28aaSamw * are not supported. In that case just allow access to the 952*da6c28aaSamw * transient directory. 953*da6c28aaSamw */ 954*da6c28aaSamw return ((error == ENOENT || error == EINVAL) ? 0 : error); 955*da6c28aaSamw } 956*da6c28aaSamw 957*da6c28aaSamw static int 958*da6c28aaSamw xattr_dir_create(vnode_t *dvp, char *name, vattr_t *vap, vcexcl_t excl, 959*da6c28aaSamw int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct, 960*da6c28aaSamw vsecattr_t *vsecp) 961*da6c28aaSamw { 962*da6c28aaSamw vnode_t *pvp; 963*da6c28aaSamw int error; 964*da6c28aaSamw 965*da6c28aaSamw *vpp = NULL; 966*da6c28aaSamw 967*da6c28aaSamw /* 968*da6c28aaSamw * Don't allow creation of extended attributes with sysattr names. 969*da6c28aaSamw */ 970*da6c28aaSamw if (is_sattr_name(name)) { 971*da6c28aaSamw return (gfs_dir_lookup(dvp, name, vpp, cr)); 972*da6c28aaSamw } 973*da6c28aaSamw 974*da6c28aaSamw error = xattr_dir_realdir(dvp, &pvp, LOOKUP_XATTR|CREATE_XATTR_DIR, 975*da6c28aaSamw cr, ct); 976*da6c28aaSamw if (error == 0) { 977*da6c28aaSamw error = VOP_CREATE(pvp, name, vap, excl, mode, vpp, cr, flag, 978*da6c28aaSamw ct, vsecp); 979*da6c28aaSamw VN_RELE(pvp); 980*da6c28aaSamw } 981*da6c28aaSamw return (error); 982*da6c28aaSamw } 983*da6c28aaSamw 984*da6c28aaSamw static int 985*da6c28aaSamw xattr_dir_remove(vnode_t *dvp, char *name, cred_t *cr, caller_context_t *ct, 986*da6c28aaSamw int flags) 987*da6c28aaSamw { 988*da6c28aaSamw vnode_t *pvp; 989*da6c28aaSamw int error; 990*da6c28aaSamw 991*da6c28aaSamw if (is_sattr_name(name)) { 992*da6c28aaSamw return (EACCES); 993*da6c28aaSamw } 994*da6c28aaSamw 995*da6c28aaSamw error = xattr_dir_realdir(dvp, &pvp, LOOKUP_XATTR, cr, ct); 996*da6c28aaSamw if (error == 0) { 997*da6c28aaSamw error = VOP_REMOVE(pvp, name, cr, ct, flags); 998*da6c28aaSamw VN_RELE(pvp); 999*da6c28aaSamw } 1000*da6c28aaSamw return (error); 1001*da6c28aaSamw } 1002*da6c28aaSamw 1003*da6c28aaSamw static int 1004*da6c28aaSamw xattr_dir_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr, 1005*da6c28aaSamw caller_context_t *ct, int flags) 1006*da6c28aaSamw { 1007*da6c28aaSamw vnode_t *pvp; 1008*da6c28aaSamw int error; 1009*da6c28aaSamw 1010*da6c28aaSamw if (svp->v_flag & V_SYSATTR) { 1011*da6c28aaSamw return (EINVAL); 1012*da6c28aaSamw } 1013*da6c28aaSamw 1014*da6c28aaSamw error = xattr_dir_realdir(tdvp, &pvp, LOOKUP_XATTR, cr, ct); 1015*da6c28aaSamw if (error == 0) { 1016*da6c28aaSamw error = VOP_LINK(pvp, svp, name, cr, ct, flags); 1017*da6c28aaSamw VN_RELE(pvp); 1018*da6c28aaSamw } 1019*da6c28aaSamw return (error); 1020*da6c28aaSamw } 1021*da6c28aaSamw 1022*da6c28aaSamw static int 1023*da6c28aaSamw xattr_dir_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, 1024*da6c28aaSamw cred_t *cr, caller_context_t *ct, int flags) 1025*da6c28aaSamw { 1026*da6c28aaSamw vnode_t *spvp, *tpvp; 1027*da6c28aaSamw int error; 1028*da6c28aaSamw int held_tgt; 1029*da6c28aaSamw 1030*da6c28aaSamw if (is_sattr_name(snm) || is_sattr_name(tnm)) 1031*da6c28aaSamw return (xattr_copy(sdvp, snm, tdvp, tnm, cr, ct)); 1032*da6c28aaSamw /* 1033*da6c28aaSamw * We know that sdvp is a GFS dir, or we wouldn't be here. 1034*da6c28aaSamw * Get the real unnamed directory. 1035*da6c28aaSamw */ 1036*da6c28aaSamw error = xattr_dir_realdir(sdvp, &spvp, LOOKUP_XATTR, cr, ct); 1037*da6c28aaSamw if (error) { 1038*da6c28aaSamw return (error); 1039*da6c28aaSamw } 1040*da6c28aaSamw 1041*da6c28aaSamw if (sdvp == tdvp) { 1042*da6c28aaSamw /* 1043*da6c28aaSamw * If the source and target are the same GFS directory, the 1044*da6c28aaSamw * underlying unnamed source and target dir will be the same. 1045*da6c28aaSamw */ 1046*da6c28aaSamw tpvp = spvp; 1047*da6c28aaSamw VN_HOLD(tpvp); 1048*da6c28aaSamw held_tgt = 1; 1049*da6c28aaSamw } else if (tdvp->v_flag & V_SYSATTR) { 1050*da6c28aaSamw /* 1051*da6c28aaSamw * If the target dir is a different GFS directory, 1052*da6c28aaSamw * find its underlying unnamed dir. 1053*da6c28aaSamw */ 1054*da6c28aaSamw error = xattr_dir_realdir(tdvp, &tpvp, LOOKUP_XATTR, cr, ct); 1055*da6c28aaSamw if (error) { 1056*da6c28aaSamw VN_RELE(spvp); 1057*da6c28aaSamw return (error); 1058*da6c28aaSamw } 1059*da6c28aaSamw held_tgt = 1; 1060*da6c28aaSamw } else { 1061*da6c28aaSamw /* 1062*da6c28aaSamw * Target dir is outside of GFS, pass it on through. 1063*da6c28aaSamw */ 1064*da6c28aaSamw tpvp = tdvp; 1065*da6c28aaSamw held_tgt = 0; 1066*da6c28aaSamw } 1067*da6c28aaSamw 1068*da6c28aaSamw error = VOP_RENAME(spvp, snm, tpvp, tnm, cr, ct, flags); 1069*da6c28aaSamw 1070*da6c28aaSamw if (held_tgt) { 1071*da6c28aaSamw VN_RELE(tpvp); 1072*da6c28aaSamw } 1073*da6c28aaSamw VN_RELE(spvp); 1074*da6c28aaSamw 1075*da6c28aaSamw return (error); 1076*da6c28aaSamw } 1077*da6c28aaSamw 1078*da6c28aaSamw static int 1079*da6c28aaSamw xattr_dir_readdir(vnode_t *dvp, uio_t *uiop, cred_t *cr, int *eofp, 1080*da6c28aaSamw caller_context_t *ct, int flags) 1081*da6c28aaSamw { 1082*da6c28aaSamw vnode_t *pvp; 1083*da6c28aaSamw int error; 1084*da6c28aaSamw int local_eof = 0; 1085*da6c28aaSamw int reset_off = 0; 1086*da6c28aaSamw int has_xattrs = 0; 1087*da6c28aaSamw 1088*da6c28aaSamw if (eofp == NULL) { 1089*da6c28aaSamw eofp = &local_eof; 1090*da6c28aaSamw } 1091*da6c28aaSamw 1092*da6c28aaSamw /* 1093*da6c28aaSamw * See if there is a real extended attribute directory. 1094*da6c28aaSamw */ 1095*da6c28aaSamw error = xattr_dir_realdir(dvp, &pvp, LOOKUP_XATTR, cr, ct); 1096*da6c28aaSamw if (error == 0) { 1097*da6c28aaSamw has_xattrs = 1; 1098*da6c28aaSamw } 1099*da6c28aaSamw 1100*da6c28aaSamw /* 1101*da6c28aaSamw * Start by reading up the static entries. 1102*da6c28aaSamw */ 1103*da6c28aaSamw if (uiop->uio_loffset == 0) { 1104*da6c28aaSamw if (has_xattrs) { 1105*da6c28aaSamw /* 1106*da6c28aaSamw * If there is a real xattr dir, skip . and .. 1107*da6c28aaSamw * in the GFS dir. We'll pick them up below 1108*da6c28aaSamw * when we call into the underlying fs. 1109*da6c28aaSamw */ 1110*da6c28aaSamw uiop->uio_loffset = GFS_STATIC_ENTRY_OFFSET; 1111*da6c28aaSamw } 1112*da6c28aaSamw error = gfs_dir_readdir(dvp, uiop, eofp, NULL, cr, ct); 1113*da6c28aaSamw if (error) { 1114*da6c28aaSamw if (has_xattrs) { 1115*da6c28aaSamw VN_RELE(pvp); 1116*da6c28aaSamw } 1117*da6c28aaSamw return (error); 1118*da6c28aaSamw } 1119*da6c28aaSamw /* 1120*da6c28aaSamw * We must read all of the static entries in the first 1121*da6c28aaSamw * call. Otherwise we won't know if uio_loffset in a 1122*da6c28aaSamw * subsequent call refers to the static entries or to those 1123*da6c28aaSamw * in an underlying fs. 1124*da6c28aaSamw */ 1125*da6c28aaSamw ASSERT(*eofp); 1126*da6c28aaSamw reset_off = 1; 1127*da6c28aaSamw } 1128*da6c28aaSamw 1129*da6c28aaSamw if (!has_xattrs) { 1130*da6c28aaSamw *eofp = 1; 1131*da6c28aaSamw return (0); 1132*da6c28aaSamw } 1133*da6c28aaSamw 1134*da6c28aaSamw *eofp = 0; 1135*da6c28aaSamw if (reset_off) { 1136*da6c28aaSamw uiop->uio_loffset = 0; 1137*da6c28aaSamw } 1138*da6c28aaSamw (void) VOP_RWLOCK(pvp, V_WRITELOCK_FALSE, NULL); 1139*da6c28aaSamw error = VOP_READDIR(pvp, uiop, cr, eofp, ct, flags); 1140*da6c28aaSamw VOP_RWUNLOCK(pvp, V_WRITELOCK_FALSE, NULL); 1141*da6c28aaSamw VN_RELE(pvp); 1142*da6c28aaSamw 1143*da6c28aaSamw return (error); 1144*da6c28aaSamw } 1145*da6c28aaSamw 1146*da6c28aaSamw /* ARGSUSED */ 1147*da6c28aaSamw static void 1148*da6c28aaSamw xattr_dir_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct) 1149*da6c28aaSamw { 1150*da6c28aaSamw gfs_file_t *fp; 1151*da6c28aaSamw 1152*da6c28aaSamw fp = gfs_dir_inactive(vp); 1153*da6c28aaSamw if (fp != NULL) { 1154*da6c28aaSamw kmem_free(fp, fp->gfs_size); 1155*da6c28aaSamw } 1156*da6c28aaSamw } 1157*da6c28aaSamw 1158*da6c28aaSamw static int 1159*da6c28aaSamw xattr_dir_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr, 1160*da6c28aaSamw caller_context_t *ct) 1161*da6c28aaSamw { 1162*da6c28aaSamw switch (cmd) { 1163*da6c28aaSamw case _PC_XATTR_EXISTS: 1164*da6c28aaSamw case _PC_SATTR_ENABLED: 1165*da6c28aaSamw case _PC_SATTR_EXISTS: 1166*da6c28aaSamw *valp = 0; 1167*da6c28aaSamw return (0); 1168*da6c28aaSamw default: 1169*da6c28aaSamw return (fs_pathconf(vp, cmd, valp, cr, ct)); 1170*da6c28aaSamw } 1171*da6c28aaSamw } 1172*da6c28aaSamw 1173*da6c28aaSamw static const fs_operation_def_t xattr_dir_tops[] = { 1174*da6c28aaSamw { VOPNAME_OPEN, { .vop_open = xattr_dir_open } }, 1175*da6c28aaSamw { VOPNAME_CLOSE, { .vop_close = xattr_dir_close } }, 1176*da6c28aaSamw { VOPNAME_IOCTL, { .error = fs_inval } }, 1177*da6c28aaSamw { VOPNAME_GETATTR, { .vop_getattr = xattr_dir_getattr } }, 1178*da6c28aaSamw { VOPNAME_SETATTR, { .vop_setattr = xattr_dir_setattr } }, 1179*da6c28aaSamw { VOPNAME_ACCESS, { .vop_access = xattr_dir_access } }, 1180*da6c28aaSamw { VOPNAME_READDIR, { .vop_readdir = xattr_dir_readdir } }, 1181*da6c28aaSamw { VOPNAME_LOOKUP, { .vop_lookup = gfs_vop_lookup } }, 1182*da6c28aaSamw { VOPNAME_CREATE, { .vop_create = xattr_dir_create } }, 1183*da6c28aaSamw { VOPNAME_REMOVE, { .vop_remove = xattr_dir_remove } }, 1184*da6c28aaSamw { VOPNAME_LINK, { .vop_link = xattr_dir_link } }, 1185*da6c28aaSamw { VOPNAME_RENAME, { .vop_rename = xattr_dir_rename } }, 1186*da6c28aaSamw { VOPNAME_MKDIR, { .error = fs_inval } }, 1187*da6c28aaSamw { VOPNAME_SEEK, { .vop_seek = fs_seek } }, 1188*da6c28aaSamw { VOPNAME_INACTIVE, { .vop_inactive = xattr_dir_inactive } }, 1189*da6c28aaSamw { VOPNAME_FID, { .vop_fid = xattr_common_fid } }, 1190*da6c28aaSamw { VOPNAME_PATHCONF, { .vop_pathconf = xattr_dir_pathconf } }, 1191*da6c28aaSamw { NULL, NULL } 1192*da6c28aaSamw }; 1193*da6c28aaSamw 1194*da6c28aaSamw static gfs_opsvec_t xattr_opsvec[] = { 1195*da6c28aaSamw { "xattr dir", xattr_dir_tops, &xattr_dir_ops }, 1196*da6c28aaSamw { "system attributes", xattr_file_tops, &xattr_file_ops }, 1197*da6c28aaSamw { NULL, NULL, NULL } 1198*da6c28aaSamw }; 1199*da6c28aaSamw 1200*da6c28aaSamw static int 1201*da6c28aaSamw xattr_lookup_cb(vnode_t *vp, const char *nm, vnode_t **vpp, ino64_t *inop, 1202*da6c28aaSamw cred_t *cr) 1203*da6c28aaSamw { 1204*da6c28aaSamw vnode_t *pvp; 1205*da6c28aaSamw struct pathname pn; 1206*da6c28aaSamw int error; 1207*da6c28aaSamw 1208*da6c28aaSamw *vpp = NULL; 1209*da6c28aaSamw *inop = 0; 1210*da6c28aaSamw 1211*da6c28aaSamw error = xattr_dir_realdir(vp, &pvp, LOOKUP_XATTR|CREATE_XATTR_DIR, 1212*da6c28aaSamw cr, NULL); 1213*da6c28aaSamw 1214*da6c28aaSamw /* 1215*da6c28aaSamw * Return ENOENT for EACCES requests during lookup. Once an 1216*da6c28aaSamw * attribute create is attempted EACCES will be returned. 1217*da6c28aaSamw */ 1218*da6c28aaSamw if (error) { 1219*da6c28aaSamw if (error == EACCES) 1220*da6c28aaSamw return (ENOENT); 1221*da6c28aaSamw return (error); 1222*da6c28aaSamw } 1223*da6c28aaSamw 1224*da6c28aaSamw error = pn_get((char *)nm, UIO_SYSSPACE, &pn); 1225*da6c28aaSamw if (error == 0) { 1226*da6c28aaSamw error = VOP_LOOKUP(pvp, (char *)nm, vpp, &pn, 0, rootvp, 1227*da6c28aaSamw cr, NULL, NULL, NULL); 1228*da6c28aaSamw pn_free(&pn); 1229*da6c28aaSamw } 1230*da6c28aaSamw VN_RELE(pvp); 1231*da6c28aaSamw 1232*da6c28aaSamw return (error); 1233*da6c28aaSamw } 1234*da6c28aaSamw 1235*da6c28aaSamw /* ARGSUSED */ 1236*da6c28aaSamw static ino64_t 1237*da6c28aaSamw xattrdir_do_ino(vnode_t *vp, int index) 1238*da6c28aaSamw { 1239*da6c28aaSamw /* 1240*da6c28aaSamw * We use index 0 for the directory fid. Start 1241*da6c28aaSamw * the file numbering at 1. 1242*da6c28aaSamw */ 1243*da6c28aaSamw return ((ino64_t)index+1); 1244*da6c28aaSamw } 1245*da6c28aaSamw 1246*da6c28aaSamw void 1247*da6c28aaSamw xattr_init(void) 1248*da6c28aaSamw { 1249*da6c28aaSamw VERIFY(gfs_make_opsvec(xattr_opsvec) == 0); 1250*da6c28aaSamw } 1251*da6c28aaSamw 1252*da6c28aaSamw int 1253*da6c28aaSamw xattr_dir_lookup(vnode_t *dvp, vnode_t **vpp, int flags, cred_t *cr) 1254*da6c28aaSamw { 1255*da6c28aaSamw int error = 0; 1256*da6c28aaSamw 1257*da6c28aaSamw *vpp = NULL; 1258*da6c28aaSamw 1259*da6c28aaSamw if (dvp->v_type != VDIR && dvp->v_type != VREG) 1260*da6c28aaSamw return (EINVAL); 1261*da6c28aaSamw 1262*da6c28aaSamw mutex_enter(&dvp->v_lock); 1263*da6c28aaSamw 1264*da6c28aaSamw /* 1265*da6c28aaSamw * If we're already in sysattr space, don't allow creation 1266*da6c28aaSamw * of another level of sysattrs. 1267*da6c28aaSamw */ 1268*da6c28aaSamw if (dvp->v_flag & V_SYSATTR) { 1269*da6c28aaSamw mutex_exit(&dvp->v_lock); 1270*da6c28aaSamw return (EINVAL); 1271*da6c28aaSamw } 1272*da6c28aaSamw 1273*da6c28aaSamw if (dvp->v_xattrdir != NULL) { 1274*da6c28aaSamw *vpp = dvp->v_xattrdir; 1275*da6c28aaSamw VN_HOLD(*vpp); 1276*da6c28aaSamw } else { 1277*da6c28aaSamw ulong_t val; 1278*da6c28aaSamw int xattrs_allowed = dvp->v_vfsp->vfs_flag & VFS_XATTR; 1279*da6c28aaSamw int sysattrs_allowed = 1; 1280*da6c28aaSamw 1281*da6c28aaSamw /* 1282*da6c28aaSamw * We have to drop the lock on dvp. gfs_dir_create will 1283*da6c28aaSamw * grab it for a VN_HOLD. 1284*da6c28aaSamw */ 1285*da6c28aaSamw mutex_exit(&dvp->v_lock); 1286*da6c28aaSamw 1287*da6c28aaSamw /* 1288*da6c28aaSamw * If dvp allows xattr creation, but not sysattr 1289*da6c28aaSamw * creation, return the real xattr dir vp. We can't 1290*da6c28aaSamw * use the vfs feature mask here because _PC_SATTR_ENABLED 1291*da6c28aaSamw * has vnode-level granularity (e.g. .zfs). 1292*da6c28aaSamw */ 1293*da6c28aaSamw error = VOP_PATHCONF(dvp, _PC_SATTR_ENABLED, &val, cr, NULL); 1294*da6c28aaSamw if (error != 0 || val == 0) 1295*da6c28aaSamw sysattrs_allowed = 0; 1296*da6c28aaSamw 1297*da6c28aaSamw if (!xattrs_allowed && !sysattrs_allowed) 1298*da6c28aaSamw return (EINVAL); 1299*da6c28aaSamw 1300*da6c28aaSamw if (!sysattrs_allowed) { 1301*da6c28aaSamw struct pathname pn; 1302*da6c28aaSamw char *nm = ""; 1303*da6c28aaSamw 1304*da6c28aaSamw error = pn_get(nm, UIO_SYSSPACE, &pn); 1305*da6c28aaSamw if (error) 1306*da6c28aaSamw return (error); 1307*da6c28aaSamw error = VOP_LOOKUP(dvp, nm, vpp, &pn, 1308*da6c28aaSamw flags|LOOKUP_HAVE_SYSATTR_DIR, rootvp, cr, NULL, 1309*da6c28aaSamw NULL, NULL); 1310*da6c28aaSamw pn_free(&pn); 1311*da6c28aaSamw return (error); 1312*da6c28aaSamw } 1313*da6c28aaSamw 1314*da6c28aaSamw /* 1315*da6c28aaSamw * Note that we act as if we were given CREATE_XATTR_DIR, 1316*da6c28aaSamw * but only for creation of the GFS directory. 1317*da6c28aaSamw */ 1318*da6c28aaSamw *vpp = gfs_dir_create( 1319*da6c28aaSamw sizeof (gfs_dir_t), dvp, xattr_dir_ops, xattr_dirents, 1320*da6c28aaSamw xattrdir_do_ino, MAXNAMELEN, NULL, xattr_lookup_cb); 1321*da6c28aaSamw mutex_enter(&dvp->v_lock); 1322*da6c28aaSamw if (dvp->v_xattrdir != NULL) { 1323*da6c28aaSamw /* 1324*da6c28aaSamw * We lost the race to create the xattr dir. 1325*da6c28aaSamw * Destroy this one, use the winner. We can't 1326*da6c28aaSamw * just call VN_RELE(*vpp), because the vnode 1327*da6c28aaSamw * is only partially initialized. 1328*da6c28aaSamw */ 1329*da6c28aaSamw gfs_dir_t *dp = (*vpp)->v_data; 1330*da6c28aaSamw 1331*da6c28aaSamw ASSERT((*vpp)->v_count == 1); 1332*da6c28aaSamw vn_free(*vpp); 1333*da6c28aaSamw 1334*da6c28aaSamw mutex_destroy(&dp->gfsd_lock); 1335*da6c28aaSamw kmem_free(dp->gfsd_static, 1336*da6c28aaSamw dp->gfsd_nstatic * sizeof (gfs_dirent_t)); 1337*da6c28aaSamw kmem_free(dp, dp->gfsd_file.gfs_size); 1338*da6c28aaSamw 1339*da6c28aaSamw /* 1340*da6c28aaSamw * There is an implied VN_HOLD(dvp) here. We should 1341*da6c28aaSamw * be doing a VN_RELE(dvp) to clean up the reference 1342*da6c28aaSamw * from *vpp, and then a VN_HOLD(dvp) for the new 1343*da6c28aaSamw * reference. Instead, we just leave the count alone. 1344*da6c28aaSamw */ 1345*da6c28aaSamw 1346*da6c28aaSamw *vpp = dvp->v_xattrdir; 1347*da6c28aaSamw VN_HOLD(*vpp); 1348*da6c28aaSamw } else { 1349*da6c28aaSamw (*vpp)->v_flag |= (V_XATTRDIR|V_SYSATTR); 1350*da6c28aaSamw dvp->v_xattrdir = *vpp; 1351*da6c28aaSamw } 1352*da6c28aaSamw } 1353*da6c28aaSamw mutex_exit(&dvp->v_lock); 1354*da6c28aaSamw 1355*da6c28aaSamw return (error); 1356*da6c28aaSamw } 1357*da6c28aaSamw 1358*da6c28aaSamw int 1359*da6c28aaSamw xattr_dir_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp) 1360*da6c28aaSamw { 1361*da6c28aaSamw int error; 1362*da6c28aaSamw vnode_t *pvp, *dvp; 1363*da6c28aaSamw xattr_fid_t *xfidp; 1364*da6c28aaSamw struct pathname pn; 1365*da6c28aaSamw char *nm; 1366*da6c28aaSamw uint16_t orig_len; 1367*da6c28aaSamw 1368*da6c28aaSamw *vpp = NULL; 1369*da6c28aaSamw 1370*da6c28aaSamw if (fidp->fid_len < XATTR_FIDSZ) 1371*da6c28aaSamw return (EINVAL); 1372*da6c28aaSamw 1373*da6c28aaSamw xfidp = (xattr_fid_t *)fidp; 1374*da6c28aaSamw orig_len = fidp->fid_len; 1375*da6c28aaSamw fidp->fid_len = xfidp->parent_len; 1376*da6c28aaSamw 1377*da6c28aaSamw error = VFS_VGET(vfsp, &pvp, fidp); 1378*da6c28aaSamw fidp->fid_len = orig_len; 1379*da6c28aaSamw if (error) 1380*da6c28aaSamw return (error); 1381*da6c28aaSamw 1382*da6c28aaSamw /* 1383*da6c28aaSamw * Start by getting the GFS sysattr directory. We might need 1384*da6c28aaSamw * to recreate it during the VOP_LOOKUP. 1385*da6c28aaSamw */ 1386*da6c28aaSamw nm = ""; 1387*da6c28aaSamw error = pn_get(nm, UIO_SYSSPACE, &pn); 1388*da6c28aaSamw if (error) { 1389*da6c28aaSamw VN_RELE(pvp); 1390*da6c28aaSamw return (EINVAL); 1391*da6c28aaSamw } 1392*da6c28aaSamw 1393*da6c28aaSamw error = VOP_LOOKUP(pvp, nm, &dvp, &pn, LOOKUP_XATTR|CREATE_XATTR_DIR, 1394*da6c28aaSamw rootvp, CRED(), NULL, NULL, NULL); 1395*da6c28aaSamw pn_free(&pn); 1396*da6c28aaSamw VN_RELE(pvp); 1397*da6c28aaSamw if (error) 1398*da6c28aaSamw return (error); 1399*da6c28aaSamw 1400*da6c28aaSamw if (xfidp->dir_offset == 0) { 1401*da6c28aaSamw /* 1402*da6c28aaSamw * If we were looking for the directory, we're done. 1403*da6c28aaSamw */ 1404*da6c28aaSamw *vpp = dvp; 1405*da6c28aaSamw return (0); 1406*da6c28aaSamw } 1407*da6c28aaSamw 1408*da6c28aaSamw if (xfidp->dir_offset > XATTRDIR_NENTS) { 1409*da6c28aaSamw VN_RELE(dvp); 1410*da6c28aaSamw return (EINVAL); 1411*da6c28aaSamw } 1412*da6c28aaSamw 1413*da6c28aaSamw nm = xattr_dirents[xfidp->dir_offset - 1].gfse_name; 1414*da6c28aaSamw 1415*da6c28aaSamw error = pn_get(nm, UIO_SYSSPACE, &pn); 1416*da6c28aaSamw if (error) { 1417*da6c28aaSamw VN_RELE(dvp); 1418*da6c28aaSamw return (EINVAL); 1419*da6c28aaSamw } 1420*da6c28aaSamw 1421*da6c28aaSamw error = VOP_LOOKUP(dvp, nm, vpp, &pn, 0, rootvp, CRED(), NULL, 1422*da6c28aaSamw NULL, NULL); 1423*da6c28aaSamw 1424*da6c28aaSamw pn_free(&pn); 1425*da6c28aaSamw VN_RELE(dvp); 1426*da6c28aaSamw 1427*da6c28aaSamw return (error); 1428*da6c28aaSamw } 1429