Print this page
6975745 xattr directories should be more transparent
*** 52,70 ****
xattr_view_t xattr_view;
} xattr_file_t;
typedef struct {
gfs_dir_t xattr_gfs_private;
! vnode_t *xattr_realvp; /* Only used for VOP_REALVP */
} xattr_dir_t;
- /*
- * xattr_realvp is only used for VOP_REALVP, this is so we don't
- * keep an unnecessary hold on the *real* xattr dir unless we have
- * no other choice.
- */
-
/* ARGSUSED */
static int
xattr_file_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct)
{
xattr_file_t *np = (*vpp)->v_data;
--- 52,64 ----
xattr_view_t xattr_view;
} xattr_file_t;
typedef struct {
gfs_dir_t xattr_gfs_private;
! vnode_t *xattr_realvp;
} xattr_dir_t;
/* ARGSUSED */
static int
xattr_file_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct)
{
xattr_file_t *np = (*vpp)->v_data;
*** 877,929 ****
static int
xattr_dir_realdir(vnode_t *dvp, vnode_t **realdvp, int lookup_flags,
cred_t *cr, caller_context_t *ct)
{
! vnode_t *pvp;
int error;
- struct pathname pn;
- char *startnm = "";
*realdvp = NULL;
! pvp = gfs_file_parent(dvp);
! error = pn_get(startnm, UIO_SYSSPACE, &pn);
! if (error) {
! VN_RELE(pvp);
! return (error);
! }
! /*
! * Set the LOOKUP_HAVE_SYSATTR_DIR flag so that we don't get into an
! * infinite loop with fop_lookup calling back to xattr_dir_lookup.
! */
! lookup_flags |= LOOKUP_HAVE_SYSATTR_DIR;
! error = VOP_LOOKUP(pvp, startnm, realdvp, &pn, lookup_flags,
! rootvp, cr, ct, NULL, NULL);
! pn_free(&pn);
return (error);
}
/* ARGSUSED */
static int
xattr_dir_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct)
{
if (flags & FWRITE) {
return (EACCES);
}
return (0);
}
/* ARGSUSED */
static int
! xattr_dir_close(vnode_t *vpp, int flags, int count, offset_t off, cred_t *cr,
caller_context_t *ct)
{
return (0);
}
/*
* Retrieve the attributes on an xattr directory. If there is a "real"
--- 871,946 ----
static int
xattr_dir_realdir(vnode_t *dvp, vnode_t **realdvp, int lookup_flags,
cred_t *cr, caller_context_t *ct)
{
! xattr_dir_t *xattr_dir;
int error;
*realdvp = NULL;
! if (dvp->v_type != VDIR)
! return (EINVAL);
! mutex_enter(&dvp->v_lock);
! xattr_dir = dvp->v_data;
! *realdvp = xattr_dir->xattr_realvp;
! mutex_exit(&dvp->v_lock);
! if (*realdvp != NULL) {
! VN_HOLD(*realdvp);
! error = 0;
! } else
! error = ENOENT;
return (error);
}
/* ARGSUSED */
static int
xattr_dir_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct)
{
+ vnode_t *realvp;
+ int error;
+
if (flags & FWRITE) {
return (EACCES);
}
+ /*
+ * The underlying FS may need this VOP call.
+ */
+ error = xattr_dir_realdir(*vpp, &realvp, LOOKUP_XATTR, cr, ct);
+ if (error == 0) {
+ error = VOP_OPEN(&realvp, flags, cr, ct);
+ VN_RELE(realvp);
+ if (error)
+ return (error);
+ } /* else ignore this error */
+
return (0);
}
/* ARGSUSED */
static int
! xattr_dir_close(vnode_t *vp, int flags, int count, offset_t off, cred_t *cr,
caller_context_t *ct)
{
+ vnode_t *realvp;
+ int error;
+
+ /*
+ * The underlying FS may need this VOP call.
+ */
+ error = xattr_dir_realdir(vp, &realvp, LOOKUP_XATTR, cr, ct);
+ if (error == 0) {
+ error = VOP_CLOSE(realvp, flags, count, off, cr, ct);
+ VN_RELE(realvp);
+ if (error)
+ return (error);
+ } /* else ignore this error */
+
return (0);
}
/*
* Retrieve the attributes on an xattr directory. If there is a "real"
*** 1354,1395 ****
/* ARGSUSED */
static int
xattr_dir_realvp(vnode_t *vp, vnode_t **realvp, caller_context_t *ct)
{
- xattr_dir_t *xattr_dir;
-
- mutex_enter(&vp->v_lock);
- xattr_dir = vp->v_data;
- if (xattr_dir->xattr_realvp) {
- *realvp = xattr_dir->xattr_realvp;
- mutex_exit(&vp->v_lock);
- return (0);
- } else {
- vnode_t *xdvp;
int error;
! mutex_exit(&vp->v_lock);
! if ((error = xattr_dir_realdir(vp, &xdvp,
! LOOKUP_XATTR, kcred, NULL)) == 0) {
! /*
! * verify we aren't racing with another thread
! * to find the xattr_realvp
! */
! mutex_enter(&vp->v_lock);
! if (xattr_dir->xattr_realvp == NULL) {
! xattr_dir->xattr_realvp = xdvp;
! *realvp = xdvp;
! mutex_exit(&vp->v_lock);
! } else {
! *realvp = xattr_dir->xattr_realvp;
! mutex_exit(&vp->v_lock);
! VN_RELE(xdvp);
! }
! }
return (error);
! }
}
static const fs_operation_def_t xattr_dir_tops[] = {
{ VOPNAME_OPEN, { .vop_open = xattr_dir_open } },
{ VOPNAME_CLOSE, { .vop_close = xattr_dir_close } },
--- 1371,1385 ----
/* ARGSUSED */
static int
xattr_dir_realvp(vnode_t *vp, vnode_t **realvp, caller_context_t *ct)
{
int error;
! error = xattr_dir_realdir(vp, realvp, LOOKUP_XATTR, kcred, NULL);
return (error);
!
}
static const fs_operation_def_t xattr_dir_tops[] = {
{ VOPNAME_OPEN, { .vop_open = xattr_dir_open } },
{ VOPNAME_CLOSE, { .vop_close = xattr_dir_close } },
*** 1468,1481 ****
--- 1458,1477 ----
xattr_init(void)
{
VERIFY(gfs_make_opsvec(xattr_opsvec) == 0);
}
+ /* See vnode.c: fop_lookup() */
int
xattr_dir_lookup(vnode_t *dvp, vnode_t **vpp, int flags, cred_t *cr)
{
int error = 0;
+ vnode_t *gfs_vp = NULL;
+ vnode_t *real_vp = NULL;
+ xattr_dir_t *xattr_dir;
+ struct pathname pn;
+ char *nm = "";
*vpp = NULL;
if (dvp->v_type != VDIR && dvp->v_type != VREG)
return (EINVAL);
*** 1490,1501 ****
mutex_exit(&dvp->v_lock);
return (EINVAL);
}
if (dvp->v_xattrdir != NULL) {
! *vpp = dvp->v_xattrdir;
! VN_HOLD(*vpp);
} else {
ulong_t val;
int xattrs_allowed = dvp->v_vfsp->vfs_flag & VFS_XATTR;
int sysattrs_allowed = 1;
--- 1486,1497 ----
mutex_exit(&dvp->v_lock);
return (EINVAL);
}
if (dvp->v_xattrdir != NULL) {
! gfs_vp = dvp->v_xattrdir;
! VN_HOLD(gfs_vp);
} else {
ulong_t val;
int xattrs_allowed = dvp->v_vfsp->vfs_flag & VFS_XATTR;
int sysattrs_allowed = 1;
*** 1517,1529 ****
if (!xattrs_allowed && !sysattrs_allowed)
return (EINVAL);
if (!sysattrs_allowed) {
- struct pathname pn;
- char *nm = "";
-
error = pn_get(nm, UIO_SYSSPACE, &pn);
if (error)
return (error);
error = VOP_LOOKUP(dvp, nm, vpp, &pn,
flags|LOOKUP_HAVE_SYSATTR_DIR, rootvp, cr, NULL,
--- 1513,1522 ----
*** 1534,1544 ****
/*
* Note that we act as if we were given CREATE_XATTR_DIR,
* but only for creation of the GFS directory.
*/
! *vpp = gfs_dir_create(
sizeof (xattr_dir_t), dvp, xattr_dir_ops, xattr_dirents,
xattrdir_do_ino, MAXNAMELEN, NULL, xattr_lookup_cb);
mutex_enter(&dvp->v_lock);
if (dvp->v_xattrdir != NULL) {
/*
--- 1527,1537 ----
/*
* Note that we act as if we were given CREATE_XATTR_DIR,
* but only for creation of the GFS directory.
*/
! gfs_vp = gfs_dir_create(
sizeof (xattr_dir_t), dvp, xattr_dir_ops, xattr_dirents,
xattrdir_do_ino, MAXNAMELEN, NULL, xattr_lookup_cb);
mutex_enter(&dvp->v_lock);
if (dvp->v_xattrdir != NULL) {
/*
*** 1545,1581 ****
* We lost the race to create the xattr dir.
* Destroy this one, use the winner. We can't
* just call VN_RELE(*vpp), because the vnode
* is only partially initialized.
*/
! gfs_dir_t *dp = (*vpp)->v_data;
! ASSERT((*vpp)->v_count == 1);
! vn_free(*vpp);
mutex_destroy(&dp->gfsd_lock);
kmem_free(dp->gfsd_static,
dp->gfsd_nstatic * sizeof (gfs_dirent_t));
kmem_free(dp, dp->gfsd_file.gfs_size);
/*
* There is an implied VN_HOLD(dvp) here. We should
* be doing a VN_RELE(dvp) to clean up the reference
! * from *vpp, and then a VN_HOLD(dvp) for the new
* reference. Instead, we just leave the count alone.
*/
! *vpp = dvp->v_xattrdir;
! VN_HOLD(*vpp);
} else {
! (*vpp)->v_flag |= (V_XATTRDIR|V_SYSATTR);
! dvp->v_xattrdir = *vpp;
}
}
mutex_exit(&dvp->v_lock);
! return (error);
}
int
xattr_dir_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp)
{
--- 1538,1603 ----
* We lost the race to create the xattr dir.
* Destroy this one, use the winner. We can't
* just call VN_RELE(*vpp), because the vnode
* is only partially initialized.
*/
! gfs_dir_t *dp = gfs_vp->v_data;
! ASSERT(gfs_vp->v_count == 1);
! vn_free(gfs_vp);
mutex_destroy(&dp->gfsd_lock);
kmem_free(dp->gfsd_static,
dp->gfsd_nstatic * sizeof (gfs_dirent_t));
kmem_free(dp, dp->gfsd_file.gfs_size);
/*
* There is an implied VN_HOLD(dvp) here. We should
* be doing a VN_RELE(dvp) to clean up the reference
! * from gfs_vp, and then a VN_HOLD(dvp) for the new
* reference. Instead, we just leave the count alone.
*/
! gfs_vp = dvp->v_xattrdir;
! VN_HOLD(gfs_vp);
} else {
! gfs_vp->v_flag |= (V_XATTRDIR|V_SYSATTR);
! dvp->v_xattrdir = gfs_vp;
}
}
mutex_exit(&dvp->v_lock);
! /*
! * In order to make this module relatively transparent
! * to the underlying filesystem, we need to lookup the
! * xattr dir in the lower filesystem and (if found)
! * keep a hold on it for as long as there is a hold
! * on the gfs_vp we're about to return. This hold is
! * released in xattr_dir_inactive.
! */
! xattr_dir = gfs_vp->v_data;
! if ((dvp->v_vfsp->vfs_flag & VFS_XATTR) &&
! (xattr_dir->xattr_realvp == NULL)) {
! error = pn_get(nm, UIO_SYSSPACE, &pn);
! if (error == 0) {
! error = VOP_LOOKUP(dvp, nm, &real_vp, &pn,
! flags|LOOKUP_HAVE_SYSATTR_DIR, rootvp, cr, NULL,
! NULL, NULL);
! pn_free(&pn);
! }
! if (error == 0) {
! mutex_enter(&gfs_vp->v_lock);
! if (xattr_dir->xattr_realvp == NULL)
! xattr_dir->xattr_realvp = real_vp;
! else
! VN_RELE(real_vp);
! mutex_exit(&gfs_vp->v_lock);
! }
! }
!
! *vpp = gfs_vp;
! return (0);
}
int
xattr_dir_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp)
{