Print this page
6975745 xattr directories should be more transparent


  37 #include <sys/file.h>
  38 #include <sys/sunddi.h>
  39 #include <sys/debug.h>
  40 #include <sys/cmn_err.h>
  41 #include <sys/vnode.h>
  42 #include <sys/mode.h>
  43 #include <sys/nvpair.h>
  44 #include <sys/attr.h>
  45 #include <sys/gfs.h>
  46 #include <sys/mutex.h>
  47 #include <fs/fs_subr.h>
  48 #include <sys/kidmap.h>
  49 
  50 typedef struct {
  51         gfs_file_t      xattr_gfs_private;
  52         xattr_view_t    xattr_view;
  53 } xattr_file_t;
  54 
  55 typedef struct {
  56         gfs_dir_t       xattr_gfs_private;
  57         vnode_t         *xattr_realvp;  /* Only used for VOP_REALVP */
  58 } xattr_dir_t;
  59 
  60 /*
  61  * xattr_realvp is only used for VOP_REALVP, this is so we don't
  62  * keep an unnecessary hold on the *real* xattr dir unless we have
  63  * no other choice.
  64  */
  65 
  66 /* ARGSUSED */
  67 static int
  68 xattr_file_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct)
  69 {
  70         xattr_file_t *np = (*vpp)->v_data;
  71 
  72         if ((np->xattr_view == XATTR_VIEW_READONLY) && (flags & FWRITE))
  73                 return (EACCES);
  74 
  75         return (0);
  76 }
  77 
  78 /* ARGSUSED */
  79 static int
  80 xattr_file_access(vnode_t *vp, int mode, int flags, cred_t *cr,
  81     caller_context_t *ct)
  82 {
  83         xattr_file_t *np = vp->v_data;
  84 
  85         if ((np->xattr_view == XATTR_VIEW_READONLY) && (mode & VWRITE))


 862         XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED);
 863         XVA_SET_REQ(&xvattr, XAT_CREATETIME);
 864         XVA_SET_REQ(&xvattr, XAT_REPARSE);
 865         XVA_SET_REQ(&xvattr, XAT_OFFLINE);
 866         XVA_SET_REQ(&xvattr, XAT_SPARSE);
 867 
 868         pdvp = gfs_file_parent(sdvp);
 869         error = VOP_GETATTR(pdvp, &xvattr.xva_vattr, 0, cr, ct);
 870         if (error)
 871                 return (error);
 872 
 873         pdvp = gfs_file_parent(tdvp);
 874         error = VOP_SETATTR(pdvp, &xvattr.xva_vattr, 0, cr, ct);
 875         return (error);
 876 }
 877 
 878 static int
 879 xattr_dir_realdir(vnode_t *dvp, vnode_t **realdvp, int lookup_flags,
 880     cred_t *cr, caller_context_t *ct)
 881 {
 882         vnode_t *pvp;
 883         int error;
 884         struct pathname pn;
 885         char *startnm = "";
 886 
 887         *realdvp = NULL;
 888 
 889         pvp = gfs_file_parent(dvp);

 890 
 891         error = pn_get(startnm, UIO_SYSSPACE, &pn);
 892         if (error) {
 893                 VN_RELE(pvp);
 894                 return (error);
 895         }
 896 
 897         /*
 898          * Set the LOOKUP_HAVE_SYSATTR_DIR flag so that we don't get into an
 899          * infinite loop with fop_lookup calling back to xattr_dir_lookup.
 900          */
 901         lookup_flags |= LOOKUP_HAVE_SYSATTR_DIR;
 902         error = VOP_LOOKUP(pvp, startnm, realdvp, &pn, lookup_flags,
 903             rootvp, cr, ct, NULL, NULL);
 904         pn_free(&pn);
 905 
 906         return (error);
 907 }
 908 
 909 /* ARGSUSED */
 910 static int
 911 xattr_dir_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct)
 912 {



 913         if (flags & FWRITE) {
 914                 return (EACCES);
 915         }
 916 











 917         return (0);
 918 }
 919 
 920 /* ARGSUSED */
 921 static int
 922 xattr_dir_close(vnode_t *vpp, int flags, int count, offset_t off, cred_t *cr,
 923     caller_context_t *ct)
 924 {














 925         return (0);
 926 }
 927 
 928 /*
 929  * Retrieve the attributes on an xattr directory.  If there is a "real"
 930  * xattr directory, use that.  Otherwise, get the attributes (represented
 931  * by PARENT_ATTRMASK) from the "parent" node and fill in the rest.  Note
 932  * that VOP_GETATTR() could turn off bits in the va_mask.
 933  */
 934 
 935 #define PARENT_ATTRMASK (AT_UID|AT_GID|AT_RDEV|AT_CTIME|AT_MTIME)
 936 
 937 /* ARGSUSED */
 938 static int
 939 xattr_dir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
 940     caller_context_t *ct)
 941 {
 942         timestruc_t now;
 943         vnode_t *pvp;
 944         int error;


1339 
1340 static int
1341 xattr_dir_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
1342     caller_context_t *ct)
1343 {
1344         switch (cmd) {
1345         case _PC_XATTR_EXISTS:
1346         case _PC_SATTR_ENABLED:
1347         case _PC_SATTR_EXISTS:
1348                 *valp = 0;
1349                 return (0);
1350         default:
1351                 return (fs_pathconf(vp, cmd, valp, cr, ct));
1352         }
1353 }
1354 
1355 /* ARGSUSED */
1356 static int
1357 xattr_dir_realvp(vnode_t *vp, vnode_t **realvp, caller_context_t *ct)
1358 {
1359         xattr_dir_t *xattr_dir;
1360 
1361         mutex_enter(&vp->v_lock);
1362         xattr_dir = vp->v_data;
1363         if (xattr_dir->xattr_realvp) {
1364                 *realvp = xattr_dir->xattr_realvp;
1365                 mutex_exit(&vp->v_lock);
1366                 return (0);
1367         } else {
1368                 vnode_t *xdvp;
1369                 int error;
1370 
1371                 mutex_exit(&vp->v_lock);
1372                 if ((error = xattr_dir_realdir(vp, &xdvp,
1373                     LOOKUP_XATTR, kcred, NULL)) == 0) {
1374                         /*
1375                          * verify we aren't racing with another thread
1376                          * to find the xattr_realvp
1377                          */
1378                         mutex_enter(&vp->v_lock);
1379                         if (xattr_dir->xattr_realvp == NULL) {
1380                                 xattr_dir->xattr_realvp = xdvp;
1381                                 *realvp = xdvp;
1382                                 mutex_exit(&vp->v_lock);
1383                         } else {
1384                                 *realvp = xattr_dir->xattr_realvp;
1385                                 mutex_exit(&vp->v_lock);
1386                                 VN_RELE(xdvp);
1387                         }
1388                 }
1389                 return (error);
1390         }
1391 }
1392 
1393 static const fs_operation_def_t xattr_dir_tops[] = {
1394         { VOPNAME_OPEN,         { .vop_open = xattr_dir_open }          },
1395         { VOPNAME_CLOSE,        { .vop_close = xattr_dir_close }        },
1396         { VOPNAME_IOCTL,        { .error = fs_inval }                   },
1397         { VOPNAME_GETATTR,      { .vop_getattr = xattr_dir_getattr }    },
1398         { VOPNAME_SETATTR,      { .vop_setattr = xattr_dir_setattr }    },
1399         { VOPNAME_ACCESS,       { .vop_access = xattr_dir_access }      },
1400         { VOPNAME_READDIR,      { .vop_readdir = xattr_dir_readdir }    },
1401         { VOPNAME_LOOKUP,       { .vop_lookup = gfs_vop_lookup }        },
1402         { VOPNAME_CREATE,       { .vop_create = xattr_dir_create }      },
1403         { VOPNAME_REMOVE,       { .vop_remove = xattr_dir_remove }      },
1404         { VOPNAME_LINK,         { .vop_link = xattr_dir_link }          },
1405         { VOPNAME_RENAME,       { .vop_rename = xattr_dir_rename }      },
1406         { VOPNAME_MKDIR,        { .error = fs_inval }                   },
1407         { VOPNAME_SEEK,         { .vop_seek = fs_seek }                 },
1408         { VOPNAME_INACTIVE,     { .vop_inactive = xattr_dir_inactive }  },
1409         { VOPNAME_FID,          { .vop_fid = xattr_common_fid }         },
1410         { VOPNAME_PATHCONF,     { .vop_pathconf = xattr_dir_pathconf }  },


1453         return (error);
1454 }
1455 
1456 /* ARGSUSED */
1457 static ino64_t
1458 xattrdir_do_ino(vnode_t *vp, int index)
1459 {
1460         /*
1461          * We use index 0 for the directory fid.  Start
1462          * the file numbering at 1.
1463          */
1464         return ((ino64_t)index+1);
1465 }
1466 
1467 void
1468 xattr_init(void)
1469 {
1470         VERIFY(gfs_make_opsvec(xattr_opsvec) == 0);
1471 }
1472 

1473 int
1474 xattr_dir_lookup(vnode_t *dvp, vnode_t **vpp, int flags, cred_t *cr)
1475 {
1476         int error = 0;





1477 
1478         *vpp = NULL;
1479 
1480         if (dvp->v_type != VDIR && dvp->v_type != VREG)
1481                 return (EINVAL);
1482 
1483         mutex_enter(&dvp->v_lock);
1484 
1485         /*
1486          * If we're already in sysattr space, don't allow creation
1487          * of another level of sysattrs.
1488          */
1489         if (dvp->v_flag & V_SYSATTR) {
1490                 mutex_exit(&dvp->v_lock);
1491                 return (EINVAL);
1492         }
1493 
1494         if (dvp->v_xattrdir != NULL) {
1495                 *vpp = dvp->v_xattrdir;
1496                 VN_HOLD(*vpp);
1497         } else {
1498                 ulong_t val;
1499                 int xattrs_allowed = dvp->v_vfsp->vfs_flag & VFS_XATTR;
1500                 int sysattrs_allowed = 1;
1501 
1502                 /*
1503                  * We have to drop the lock on dvp.  gfs_dir_create will
1504                  * grab it for a VN_HOLD.
1505                  */
1506                 mutex_exit(&dvp->v_lock);
1507 
1508                 /*
1509                  * If dvp allows xattr creation, but not sysattr
1510                  * creation, return the real xattr dir vp. We can't
1511                  * use the vfs feature mask here because _PC_SATTR_ENABLED
1512                  * has vnode-level granularity (e.g. .zfs).
1513                  */
1514                 error = VOP_PATHCONF(dvp, _PC_SATTR_ENABLED, &val, cr, NULL);
1515                 if (error != 0 || val == 0)
1516                         sysattrs_allowed = 0;
1517 
1518                 if (!xattrs_allowed && !sysattrs_allowed)
1519                         return (EINVAL);
1520 
1521                 if (!sysattrs_allowed) {
1522                         struct pathname pn;
1523                         char *nm = "";
1524 
1525                         error = pn_get(nm, UIO_SYSSPACE, &pn);
1526                         if (error)
1527                                 return (error);
1528                         error = VOP_LOOKUP(dvp, nm, vpp, &pn,
1529                             flags|LOOKUP_HAVE_SYSATTR_DIR, rootvp, cr, NULL,
1530                             NULL, NULL);
1531                         pn_free(&pn);
1532                         return (error);
1533                 }
1534 
1535                 /*
1536                  * Note that we act as if we were given CREATE_XATTR_DIR,
1537                  * but only for creation of the GFS directory.
1538                  */
1539                 *vpp = gfs_dir_create(
1540                     sizeof (xattr_dir_t), dvp, xattr_dir_ops, xattr_dirents,
1541                     xattrdir_do_ino, MAXNAMELEN, NULL, xattr_lookup_cb);
1542                 mutex_enter(&dvp->v_lock);
1543                 if (dvp->v_xattrdir != NULL) {
1544                         /*
1545                          * We lost the race to create the xattr dir.
1546                          * Destroy this one, use the winner.  We can't
1547                          * just call VN_RELE(*vpp), because the vnode
1548                          * is only partially initialized.
1549                          */
1550                         gfs_dir_t *dp = (*vpp)->v_data;
1551 
1552                         ASSERT((*vpp)->v_count == 1);
1553                         vn_free(*vpp);
1554 
1555                         mutex_destroy(&dp->gfsd_lock);
1556                         kmem_free(dp->gfsd_static,
1557                             dp->gfsd_nstatic * sizeof (gfs_dirent_t));
1558                         kmem_free(dp, dp->gfsd_file.gfs_size);
1559 
1560                         /*
1561                          * There is an implied VN_HOLD(dvp) here.  We should
1562                          * be doing a VN_RELE(dvp) to clean up the reference
1563                          * from *vpp, and then a VN_HOLD(dvp) for the new
1564                          * reference.  Instead, we just leave the count alone.
1565                          */
1566 
1567                         *vpp = dvp->v_xattrdir;
1568                         VN_HOLD(*vpp);
1569                 } else {
1570                         (*vpp)->v_flag |= (V_XATTRDIR|V_SYSATTR);
1571                         dvp->v_xattrdir = *vpp;
1572                 }
1573         }
1574         mutex_exit(&dvp->v_lock);
1575 
1576         return (error);





























1577 }
1578 
1579 int
1580 xattr_dir_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp)
1581 {
1582         int error;
1583         vnode_t *pvp, *dvp;
1584         xattr_fid_t *xfidp;
1585         struct pathname pn;
1586         char *nm;
1587         uint16_t orig_len;
1588 
1589         *vpp = NULL;
1590 
1591         if (fidp->fid_len < XATTR_FIDSZ)
1592                 return (EINVAL);
1593 
1594         xfidp = (xattr_fid_t *)fidp;
1595         orig_len = fidp->fid_len;
1596         fidp->fid_len = xfidp->parent_len;




  37 #include <sys/file.h>
  38 #include <sys/sunddi.h>
  39 #include <sys/debug.h>
  40 #include <sys/cmn_err.h>
  41 #include <sys/vnode.h>
  42 #include <sys/mode.h>
  43 #include <sys/nvpair.h>
  44 #include <sys/attr.h>
  45 #include <sys/gfs.h>
  46 #include <sys/mutex.h>
  47 #include <fs/fs_subr.h>
  48 #include <sys/kidmap.h>
  49 
  50 typedef struct {
  51         gfs_file_t      xattr_gfs_private;
  52         xattr_view_t    xattr_view;
  53 } xattr_file_t;
  54 
  55 typedef struct {
  56         gfs_dir_t       xattr_gfs_private;
  57         vnode_t         *xattr_realvp;
  58 } xattr_dir_t;
  59 






  60 /* ARGSUSED */
  61 static int
  62 xattr_file_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct)
  63 {
  64         xattr_file_t *np = (*vpp)->v_data;
  65 
  66         if ((np->xattr_view == XATTR_VIEW_READONLY) && (flags & FWRITE))
  67                 return (EACCES);
  68 
  69         return (0);
  70 }
  71 
  72 /* ARGSUSED */
  73 static int
  74 xattr_file_access(vnode_t *vp, int mode, int flags, cred_t *cr,
  75     caller_context_t *ct)
  76 {
  77         xattr_file_t *np = vp->v_data;
  78 
  79         if ((np->xattr_view == XATTR_VIEW_READONLY) && (mode & VWRITE))


 856         XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED);
 857         XVA_SET_REQ(&xvattr, XAT_CREATETIME);
 858         XVA_SET_REQ(&xvattr, XAT_REPARSE);
 859         XVA_SET_REQ(&xvattr, XAT_OFFLINE);
 860         XVA_SET_REQ(&xvattr, XAT_SPARSE);
 861 
 862         pdvp = gfs_file_parent(sdvp);
 863         error = VOP_GETATTR(pdvp, &xvattr.xva_vattr, 0, cr, ct);
 864         if (error)
 865                 return (error);
 866 
 867         pdvp = gfs_file_parent(tdvp);
 868         error = VOP_SETATTR(pdvp, &xvattr.xva_vattr, 0, cr, ct);
 869         return (error);
 870 }
 871 
 872 static int
 873 xattr_dir_realdir(vnode_t *dvp, vnode_t **realdvp, int lookup_flags,
 874     cred_t *cr, caller_context_t *ct)
 875 {
 876         xattr_dir_t *xattr_dir;
 877         int error;


 878 
 879         *realdvp = NULL;
 880 
 881         if (dvp->v_type != VDIR)
 882                 return (EINVAL);
 883 
 884         mutex_enter(&dvp->v_lock);
 885         xattr_dir = dvp->v_data;
 886         *realdvp = xattr_dir->xattr_realvp;
 887         mutex_exit(&dvp->v_lock);

 888 
 889         if (*realdvp != NULL) {
 890                 VN_HOLD(*realdvp);
 891                 error = 0;
 892         } else
 893                 error = ENOENT;



 894 
 895         return (error);
 896 }
 897 
 898 /* ARGSUSED */
 899 static int
 900 xattr_dir_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct)
 901 {
 902         vnode_t *realvp;
 903         int error;
 904 
 905         if (flags & FWRITE) {
 906                 return (EACCES);
 907         }
 908 
 909         /*
 910          * The underlying FS may need this VOP call.
 911          */
 912         error = xattr_dir_realdir(*vpp, &realvp, LOOKUP_XATTR, cr, ct);
 913         if (error == 0) {
 914                 error = VOP_OPEN(&realvp, flags, cr, ct);
 915                 VN_RELE(realvp);
 916                 if (error)
 917                         return (error);
 918         } /* else ignore this error */
 919 
 920         return (0);
 921 }
 922 
 923 /* ARGSUSED */
 924 static int
 925 xattr_dir_close(vnode_t *vp, int flags, int count, offset_t off, cred_t *cr,
 926     caller_context_t *ct)
 927 {
 928         vnode_t *realvp;
 929         int error;
 930 
 931         /*
 932          * The underlying FS may need this VOP call.
 933          */
 934         error = xattr_dir_realdir(vp, &realvp, LOOKUP_XATTR, cr, ct);
 935         if (error == 0) {
 936                 error = VOP_CLOSE(realvp, flags, count, off, cr, ct);
 937                 VN_RELE(realvp);
 938                 if (error)
 939                         return (error);
 940         } /* else ignore this error */
 941 
 942         return (0);
 943 }
 944 
 945 /*
 946  * Retrieve the attributes on an xattr directory.  If there is a "real"
 947  * xattr directory, use that.  Otherwise, get the attributes (represented
 948  * by PARENT_ATTRMASK) from the "parent" node and fill in the rest.  Note
 949  * that VOP_GETATTR() could turn off bits in the va_mask.
 950  */
 951 
 952 #define PARENT_ATTRMASK (AT_UID|AT_GID|AT_RDEV|AT_CTIME|AT_MTIME)
 953 
 954 /* ARGSUSED */
 955 static int
 956 xattr_dir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
 957     caller_context_t *ct)
 958 {
 959         timestruc_t now;
 960         vnode_t *pvp;
 961         int error;


1356 
1357 static int
1358 xattr_dir_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
1359     caller_context_t *ct)
1360 {
1361         switch (cmd) {
1362         case _PC_XATTR_EXISTS:
1363         case _PC_SATTR_ENABLED:
1364         case _PC_SATTR_EXISTS:
1365                 *valp = 0;
1366                 return (0);
1367         default:
1368                 return (fs_pathconf(vp, cmd, valp, cr, ct));
1369         }
1370 }
1371 
1372 /* ARGSUSED */
1373 static int
1374 xattr_dir_realvp(vnode_t *vp, vnode_t **realvp, caller_context_t *ct)
1375 {










1376         int error;
1377 
1378         error = xattr_dir_realdir(vp, realvp, LOOKUP_XATTR, kcred, NULL);

















1379         return (error);
1380 
1381 }
1382 
1383 static const fs_operation_def_t xattr_dir_tops[] = {
1384         { VOPNAME_OPEN,         { .vop_open = xattr_dir_open }          },
1385         { VOPNAME_CLOSE,        { .vop_close = xattr_dir_close }        },
1386         { VOPNAME_IOCTL,        { .error = fs_inval }                   },
1387         { VOPNAME_GETATTR,      { .vop_getattr = xattr_dir_getattr }    },
1388         { VOPNAME_SETATTR,      { .vop_setattr = xattr_dir_setattr }    },
1389         { VOPNAME_ACCESS,       { .vop_access = xattr_dir_access }      },
1390         { VOPNAME_READDIR,      { .vop_readdir = xattr_dir_readdir }    },
1391         { VOPNAME_LOOKUP,       { .vop_lookup = gfs_vop_lookup }        },
1392         { VOPNAME_CREATE,       { .vop_create = xattr_dir_create }      },
1393         { VOPNAME_REMOVE,       { .vop_remove = xattr_dir_remove }      },
1394         { VOPNAME_LINK,         { .vop_link = xattr_dir_link }          },
1395         { VOPNAME_RENAME,       { .vop_rename = xattr_dir_rename }      },
1396         { VOPNAME_MKDIR,        { .error = fs_inval }                   },
1397         { VOPNAME_SEEK,         { .vop_seek = fs_seek }                 },
1398         { VOPNAME_INACTIVE,     { .vop_inactive = xattr_dir_inactive }  },
1399         { VOPNAME_FID,          { .vop_fid = xattr_common_fid }         },
1400         { VOPNAME_PATHCONF,     { .vop_pathconf = xattr_dir_pathconf }  },


1443         return (error);
1444 }
1445 
1446 /* ARGSUSED */
1447 static ino64_t
1448 xattrdir_do_ino(vnode_t *vp, int index)
1449 {
1450         /*
1451          * We use index 0 for the directory fid.  Start
1452          * the file numbering at 1.
1453          */
1454         return ((ino64_t)index+1);
1455 }
1456 
1457 void
1458 xattr_init(void)
1459 {
1460         VERIFY(gfs_make_opsvec(xattr_opsvec) == 0);
1461 }
1462 
1463 /* See vnode.c: fop_lookup() */
1464 int
1465 xattr_dir_lookup(vnode_t *dvp, vnode_t **vpp, int flags, cred_t *cr)
1466 {
1467         int error = 0;
1468         vnode_t *gfs_vp = NULL;
1469         vnode_t *real_vp = NULL;
1470         xattr_dir_t *xattr_dir;
1471         struct pathname pn;
1472         char *nm = "";
1473 
1474         *vpp = NULL;
1475 
1476         if (dvp->v_type != VDIR && dvp->v_type != VREG)
1477                 return (EINVAL);
1478 
1479         mutex_enter(&dvp->v_lock);
1480 
1481         /*
1482          * If we're already in sysattr space, don't allow creation
1483          * of another level of sysattrs.
1484          */
1485         if (dvp->v_flag & V_SYSATTR) {
1486                 mutex_exit(&dvp->v_lock);
1487                 return (EINVAL);
1488         }
1489 
1490         if (dvp->v_xattrdir != NULL) {
1491                 gfs_vp = dvp->v_xattrdir;
1492                 VN_HOLD(gfs_vp);
1493         } else {
1494                 ulong_t val;
1495                 int xattrs_allowed = dvp->v_vfsp->vfs_flag & VFS_XATTR;
1496                 int sysattrs_allowed = 1;
1497 
1498                 /*
1499                  * We have to drop the lock on dvp.  gfs_dir_create will
1500                  * grab it for a VN_HOLD.
1501                  */
1502                 mutex_exit(&dvp->v_lock);
1503 
1504                 /*
1505                  * If dvp allows xattr creation, but not sysattr
1506                  * creation, return the real xattr dir vp. We can't
1507                  * use the vfs feature mask here because _PC_SATTR_ENABLED
1508                  * has vnode-level granularity (e.g. .zfs).
1509                  */
1510                 error = VOP_PATHCONF(dvp, _PC_SATTR_ENABLED, &val, cr, NULL);
1511                 if (error != 0 || val == 0)
1512                         sysattrs_allowed = 0;
1513 
1514                 if (!xattrs_allowed && !sysattrs_allowed)
1515                         return (EINVAL);
1516 
1517                 if (!sysattrs_allowed) {



1518                         error = pn_get(nm, UIO_SYSSPACE, &pn);
1519                         if (error)
1520                                 return (error);
1521                         error = VOP_LOOKUP(dvp, nm, vpp, &pn,
1522                             flags|LOOKUP_HAVE_SYSATTR_DIR, rootvp, cr, NULL,
1523                             NULL, NULL);
1524                         pn_free(&pn);
1525                         return (error);
1526                 }
1527 
1528                 /*
1529                  * Note that we act as if we were given CREATE_XATTR_DIR,
1530                  * but only for creation of the GFS directory.
1531                  */
1532                 gfs_vp = gfs_dir_create(
1533                     sizeof (xattr_dir_t), dvp, xattr_dir_ops, xattr_dirents,
1534                     xattrdir_do_ino, MAXNAMELEN, NULL, xattr_lookup_cb);
1535                 mutex_enter(&dvp->v_lock);
1536                 if (dvp->v_xattrdir != NULL) {
1537                         /*
1538                          * We lost the race to create the xattr dir.
1539                          * Destroy this one, use the winner.  We can't
1540                          * just call VN_RELE(*vpp), because the vnode
1541                          * is only partially initialized.
1542                          */
1543                         gfs_dir_t *dp = gfs_vp->v_data;
1544 
1545                         ASSERT(gfs_vp->v_count == 1);
1546                         vn_free(gfs_vp);
1547 
1548                         mutex_destroy(&dp->gfsd_lock);
1549                         kmem_free(dp->gfsd_static,
1550                             dp->gfsd_nstatic * sizeof (gfs_dirent_t));
1551                         kmem_free(dp, dp->gfsd_file.gfs_size);
1552 
1553                         /*
1554                          * There is an implied VN_HOLD(dvp) here.  We should
1555                          * be doing a VN_RELE(dvp) to clean up the reference
1556                          * from gfs_vp, and then a VN_HOLD(dvp) for the new
1557                          * reference.  Instead, we just leave the count alone.
1558                          */
1559 
1560                         gfs_vp = dvp->v_xattrdir;
1561                         VN_HOLD(gfs_vp);
1562                 } else {
1563                         gfs_vp->v_flag |= (V_XATTRDIR|V_SYSATTR);
1564                         dvp->v_xattrdir = gfs_vp;
1565                 }
1566         }
1567         mutex_exit(&dvp->v_lock);
1568 
1569         /*
1570          * In order to make this module relatively transparent
1571          * to the underlying filesystem, we need to lookup the
1572          * xattr dir in the lower filesystem and (if found)
1573          * keep a hold on it for as long as there is a hold
1574          * on the gfs_vp we're about to return.  This hold is
1575          * released in xattr_dir_inactive.
1576          */
1577         xattr_dir = gfs_vp->v_data;
1578         if ((dvp->v_vfsp->vfs_flag & VFS_XATTR) &&
1579             (xattr_dir->xattr_realvp == NULL)) {
1580                 error = pn_get(nm, UIO_SYSSPACE, &pn);
1581                 if (error == 0) {
1582                         error = VOP_LOOKUP(dvp, nm, &real_vp, &pn,
1583                             flags|LOOKUP_HAVE_SYSATTR_DIR, rootvp, cr, NULL,
1584                             NULL, NULL);
1585                         pn_free(&pn);
1586                 }
1587                 if (error == 0) {
1588                         mutex_enter(&gfs_vp->v_lock);
1589                         if (xattr_dir->xattr_realvp == NULL)
1590                                 xattr_dir->xattr_realvp = real_vp;
1591                         else
1592                                 VN_RELE(real_vp);
1593                         mutex_exit(&gfs_vp->v_lock);
1594                 }
1595         }
1596 
1597         *vpp = gfs_vp;
1598         return (0);
1599 }
1600 
1601 int
1602 xattr_dir_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp)
1603 {
1604         int error;
1605         vnode_t *pvp, *dvp;
1606         xattr_fid_t *xfidp;
1607         struct pathname pn;
1608         char *nm;
1609         uint16_t orig_len;
1610 
1611         *vpp = NULL;
1612 
1613         if (fidp->fid_len < XATTR_FIDSZ)
1614                 return (EINVAL);
1615 
1616         xfidp = (xattr_fid_t *)fidp;
1617         orig_len = fidp->fid_len;
1618         fidp->fid_len = xfidp->parent_len;