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