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;
|