Home | History | Annotate | Download | only in fs
      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, &times, &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