summaryrefslogtreecommitdiff
path: root/usr/src/uts
diff options
context:
space:
mode:
authorDai Ngo <dai.ngo@sun.com>2009-10-14 11:15:07 -0500
committerDai Ngo <dai.ngo@sun.com>2009-10-14 11:15:07 -0500
commit7a286c471efbab8562f7655a82931904703fffe0 (patch)
treebbd1ea3af4176ce7e295afaa9eb7cb86b95010c0 /usr/src/uts
parent635216b673cf196ac523ff2a7ab715717e553292 (diff)
downloadillumos-gate-7a286c471efbab8562f7655a82931904703fffe0.tar.gz
6886081 Solaris needs reparse point support (PSARC 2009/387)
PSARC 2009/387 Pathname Reparse Points
Diffstat (limited to 'usr/src/uts')
-rw-r--r--usr/src/uts/common/Makefile.files1
-rw-r--r--usr/src/uts/common/Makefile.rules7
-rw-r--r--usr/src/uts/common/fs/Makefile14
-rw-r--r--usr/src/uts/common/fs/fs_reparse.h88
-rw-r--r--usr/src/uts/common/fs/fs_subr.c181
-rw-r--r--usr/src/uts/common/fs/vfs.c4
-rw-r--r--usr/src/uts/common/fs/vnode.c46
-rw-r--r--usr/src/uts/common/fs/xattr.c13
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zfs_znode.h1
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_log.c3
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_replay.c6
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_vfsops.c1
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_vnops.c12
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_znode.c4
-rw-r--r--usr/src/uts/common/fs/zut/zut.c3
-rw-r--r--usr/src/uts/common/sys/attr.h7
-rw-r--r--usr/src/uts/common/sys/vfs.h1
-rw-r--r--usr/src/uts/common/sys/vnode.h8
18 files changed, 384 insertions, 16 deletions
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index 2c0777fc54..7d8ed8dac1 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -162,6 +162,7 @@ GENUNIX_OBJS += \
fork.o \
vpm.o \
fsat.o \
+ fs_reparse.o \
fs_subr.o \
fsflush.o \
ftrace.o \
diff --git a/usr/src/uts/common/Makefile.rules b/usr/src/uts/common/Makefile.rules
index 75354e4c62..01a28db0be 100644
--- a/usr/src/uts/common/Makefile.rules
+++ b/usr/src/uts/common/Makefile.rules
@@ -340,6 +340,10 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/io/scsi/adapters/pmcs/%.bin
$(COMPILE.b) -o $@ $<
$(CTFCONVERT_O)
+$(OBJS_DIR)/%.o: $(COMMONBASE)/fsreparse/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
KMECHKRB5_BASE=$(UTSBASE)/common/gssapi/mechs/krb5
KGSSDFLAGS=-I $(UTSBASE)/common/gssapi/include
@@ -2530,3 +2534,6 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/vr/%.c
$(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/yge/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
+
+$(LINTS_DIR)/%.ln: $(COMMONBASE)/fsreparse/%.c
+ @($(LHEAD) $(LINT.c) $< $(LTAIL))
diff --git a/usr/src/uts/common/fs/Makefile b/usr/src/uts/common/fs/Makefile
index 28ad019955..53660e655d 100644
--- a/usr/src/uts/common/fs/Makefile
+++ b/usr/src/uts/common/fs/Makefile
@@ -2,9 +2,8 @@
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License"). You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
@@ -19,17 +18,16 @@
#
# CDDL HEADER END
#
-#
-#ident "%Z%%M% %I% %E% SMI"
-#
-# Copyright (c) 1989 by Sun Microsystems, Inc.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
#
# uts/common/fs/Makefile
#
# include global definitions
include ../../../Makefile.master
-HDRS= fs_subr.h
+HDRS= fs_subr.h \
+ fs_reparse.h
PROCHDRS= prdata.h
diff --git a/usr/src/uts/common/fs/fs_reparse.h b/usr/src/uts/common/fs/fs_reparse.h
new file mode 100644
index 0000000000..ec44484117
--- /dev/null
+++ b/usr/src/uts/common/fs/fs_reparse.h
@@ -0,0 +1,88 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _FS_REPARSE_H
+#define _FS_REPARSE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#ifdef _KERNEL
+#include <sys/time.h>
+#include <sys/nvpair.h>
+#else
+#include <libnvpair.h>
+#endif
+
+#define FS_REPARSE_TAG_STR "@{REPARSE"
+#define FS_REPARSE_TAG_END_CHAR '}'
+#define FS_REPARSE_TAG_END_STR "}"
+#define FS_TOKEN_START_STR "@{"
+#define FS_TOKEN_END_STR "}"
+
+#define REPARSED "svc:/system/filesystem/reparse:default"
+#define MAXREPARSELEN MAXPATHLEN
+#define REPARSED_DOOR "/var/run/reparsed_door"
+#define REPARSED_DOORCALL_MAX_RETRY 4
+
+/*
+ * This structure is shared between kernel code and user reparsed daemon.
+ * The 'res_len' must be defined as int, and not size_t, for 32-bit reparsed
+ * binary and 64-bit kernel code to work together.
+ */
+typedef struct reparsed_door_res {
+ int res_status;
+ int res_len;
+ char res_data[1];
+} reparsed_door_res_t;
+
+extern nvlist_t *reparse_init(void);
+extern void reparse_free(nvlist_t *nvl);
+extern int reparse_parse(const char *reparse_data, nvlist_t *nvl);
+extern int reparse_validate(const char *reparse_data);
+
+#ifdef _KERNEL
+extern int reparse_kderef(const char *svc_type, const char *svc_data,
+ char *buf, size_t *bufsz);
+extern int reparse_vnode_parse(vnode_t *vp, nvlist_t *nvl);
+#else
+extern int reparse_add(nvlist_t *nvl, const char *svc_type,
+ const char *svc_data);
+extern int reparse_remove(nvlist_t *nvl, const char *svc_type);
+extern int reparse_unparse(nvlist_t *nvl, char **stringp);
+extern int reparse_create(const char *path, const char *string);
+extern int reparse_delete(const char *path);
+extern int reparse_deref(const char *svc_type, const char *svc_data,
+ char *buf, size_t *bufsz);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FS_REPARSE_H */
diff --git a/usr/src/uts/common/fs/fs_subr.c b/usr/src/uts/common/fs/fs_subr.c
index 5187ecf327..a465a97043 100644
--- a/usr/src/uts/common/fs/fs_subr.c
+++ b/usr/src/uts/common/fs/fs_subr.c
@@ -48,6 +48,8 @@
#include <sys/cmn_err.h>
#include <sys/stream.h>
#include <fs/fs_subr.h>
+#include <fs/fs_reparse.h>
+#include <sys/door.h>
#include <sys/acl.h>
#include <sys/share.h>
#include <sys/file.h>
@@ -55,6 +57,7 @@
#include <sys/file.h>
#include <sys/nbmlock.h>
#include <acl/acl_common.h>
+#include <sys/pathname.h>
static callb_cpr_t *frlock_serialize_blocked(flk_cb_when_t, void *);
@@ -64,6 +67,12 @@ static callb_cpr_t *frlock_serialize_blocked(flk_cb_when_t, void *);
int fs_estale_retry = 5;
/*
+ * supports for reparse point door upcall
+ */
+static door_handle_t reparsed_door;
+static kmutex_t reparsed_door_lock;
+
+/*
* The associated operation is not supported by the file system.
*/
int
@@ -838,3 +847,175 @@ fs_vscan(vnode_t *vp, cred_t *cr, int async)
return (ret);
}
+
+/*
+ * support functions for reparse point
+ */
+/*
+ * reparse_vnode_parse
+ *
+ * Read the symlink data of a reparse point specified by the vnode
+ * and return the reparse data as name-value pair in the nvlist.
+ */
+int
+reparse_vnode_parse(vnode_t *vp, nvlist_t *nvl)
+{
+ int err;
+ char *lkdata;
+ struct uio uio;
+ struct iovec iov;
+
+ if (vp == NULL || nvl == NULL)
+ return (EINVAL);
+
+ lkdata = kmem_alloc(MAXREPARSELEN, KM_SLEEP);
+
+ /*
+ * Set up io vector to read sym link data
+ */
+ iov.iov_base = lkdata;
+ iov.iov_len = MAXREPARSELEN;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_extflg = UIO_COPY_CACHED;
+ uio.uio_loffset = (offset_t)0;
+ uio.uio_resid = MAXREPARSELEN;
+
+ if ((err = VOP_READLINK(vp, &uio, kcred, NULL)) == 0) {
+ *(lkdata + MAXREPARSELEN - uio.uio_resid) = '\0';
+ err = reparse_parse(lkdata, nvl);
+ }
+ kmem_free(lkdata, MAXREPARSELEN); /* done with lkdata */
+
+ return (err);
+}
+
+void
+reparse_point_init()
+{
+ mutex_init(&reparsed_door_lock, NULL, MUTEX_DEFAULT, NULL);
+}
+
+static door_handle_t
+reparse_door_get_handle()
+{
+ door_handle_t dh;
+
+ mutex_enter(&reparsed_door_lock);
+ if ((dh = reparsed_door) == NULL) {
+ if (door_ki_open(REPARSED_DOOR, &reparsed_door) != 0) {
+ reparsed_door = NULL;
+ dh = NULL;
+ } else
+ dh = reparsed_door;
+ }
+ mutex_exit(&reparsed_door_lock);
+ return (dh);
+}
+
+static void
+reparse_door_reset_handle()
+{
+ mutex_enter(&reparsed_door_lock);
+ reparsed_door = NULL;
+ mutex_exit(&reparsed_door_lock);
+}
+
+/*
+ * reparse_kderef
+ *
+ * Accepts the service-specific item from the reparse point and returns
+ * the service-specific data requested. The caller specifies the size of
+ * the buffer provided via *bufsz; the routine will fail with EOVERFLOW
+ * if the results will not fit in the buffer, in which case, *bufsz will
+ * contain the number of bytes needed to hold the results.
+ *
+ * if ok return 0 and update *bufsize with length of actual result
+ * else return error code.
+ */
+int
+reparse_kderef(const char *svc_type, const char *svc_data, char *buf,
+ size_t *bufsize)
+{
+ int err, retries, need_free;
+ size_t dlen, res_len;
+ char *darg;
+ door_arg_t door_args;
+ reparsed_door_res_t *resp;
+ door_handle_t rp_door;
+
+ if (svc_type == NULL || svc_data == NULL || buf == NULL ||
+ bufsize == NULL)
+ return (EINVAL);
+
+ /* get reparsed's door handle */
+ if ((rp_door = reparse_door_get_handle()) == NULL)
+ return (EBADF);
+
+ /* setup buffer for door_call args and results */
+ dlen = strlen(svc_type) + strlen(svc_data) + 2;
+ if (*bufsize < dlen) {
+ darg = kmem_alloc(dlen, KM_SLEEP);
+ need_free = 1;
+ } else {
+ darg = buf; /* use same buffer for door's args & results */
+ need_free = 0;
+ }
+
+ /* build argument string of door call */
+ (void) snprintf(darg, dlen, "%s:%s", svc_type, svc_data);
+
+ /* setup args for door call */
+ door_args.data_ptr = darg;
+ door_args.data_size = dlen;
+ door_args.desc_ptr = NULL;
+ door_args.desc_num = 0;
+ door_args.rbuf = buf;
+ door_args.rsize = *bufsize;
+
+ /* do the door_call */
+ retries = 0;
+ door_ki_hold(rp_door);
+ while ((err = door_ki_upcall_limited(rp_door, &door_args,
+ NULL, SIZE_MAX, 0)) != 0) {
+ if (err == EAGAIN || err == EINTR) {
+ if (++retries < REPARSED_DOORCALL_MAX_RETRY) {
+ delay(SEC_TO_TICK(1));
+ continue;
+ }
+ } else if (err == EBADF) {
+ /* door server goes away... */
+ reparse_door_reset_handle();
+ }
+ break;
+ }
+ door_ki_rele(rp_door);
+ if (need_free)
+ kmem_free(darg, dlen); /* done with args buffer */
+
+ if (err != 0)
+ return (err);
+
+ resp = (reparsed_door_res_t *)door_args.rbuf;
+ if ((err = resp->res_status) == 0) {
+ /*
+ * have to save the length of the results before the
+ * bcopy below since it's can be an overlap copy that
+ * overwrites the reparsed_door_res_t structure at
+ * the beginning of the buffer.
+ */
+ res_len = (size_t)resp->res_len;
+
+ /* deref call is ok */
+ if (res_len > *bufsize)
+ err = EOVERFLOW;
+ else
+ bcopy(resp->res_data, buf, res_len);
+ *bufsize = res_len;
+ }
+ if (door_args.rbuf != buf)
+ kmem_free(door_args.rbuf, door_args.rsize);
+
+ return (err);
+}
diff --git a/usr/src/uts/common/fs/vfs.c b/usr/src/uts/common/fs/vfs.c
index bf9d325048..0d750e00ed 100644
--- a/usr/src/uts/common/fs/vfs.c
+++ b/usr/src/uts/common/fs/vfs.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -4252,6 +4252,8 @@ vfsinit(void)
}
xattr_init();
+
+ reparse_point_init();
}
vfs_t *
diff --git a/usr/src/uts/common/fs/vnode.c b/usr/src/uts/common/fs/vnode.c
index 09a011fc87..a42259df93 100644
--- a/usr/src/uts/common/fs/vnode.c
+++ b/usr/src/uts/common/fs/vnode.c
@@ -64,6 +64,7 @@
#include <sys/fcntl.h>
#include <fs/fs_subr.h>
#include <sys/taskq.h>
+#include <fs/fs_reparse.h>
/* Determine if this vnode is a file that is read-only */
#define ISROFILE(vp) \
@@ -106,6 +107,11 @@ int vopstats_enabled = 1;
static void *vsd_realloc(void *, size_t, size_t);
/*
+ * forward declarations for reparse point functions
+ */
+static int fs_reparse_mark(char *target, vattr_t *vap, xvattr_t *xvattr);
+
+/*
* VSD -- VNODE SPECIFIC DATA
* The v_data pointer is typically used by a file system to store a
* pointer to the file system's private node (e.g. ufs inode, nfs rnode).
@@ -3604,6 +3610,7 @@ fop_symlink(
int flags)
{
int err;
+ xvattr_t xvattr;
/*
* If this file system doesn't support case-insensitive access
@@ -3616,6 +3623,14 @@ fop_symlink(
VOPXID_MAP_CR(dvp, cr);
+ /* check for reparse point */
+ if ((vfs_has_feature(dvp->v_vfsp, VFSFT_REPARSE)) &&
+ (strncmp(target, FS_REPARSE_TAG_STR,
+ strlen(FS_REPARSE_TAG_STR)) == 0)) {
+ if (!fs_reparse_mark(target, vap, &xvattr))
+ vap = (vattr_t *)&xvattr;
+ }
+
err = (*(dvp)->v_op->vop_symlink)
(dvp, linkname, vap, target, cr, ct, flags);
VOPSTATS_UPDATE(dvp, symlink);
@@ -4395,3 +4410,34 @@ vsd_realloc(void *old, size_t osize, size_t nsize)
}
return (new);
}
+
+/*
+ * Setup the extensible system attribute for creating a reparse point.
+ * The symlink data 'target' is validated for proper format of a reparse
+ * string and a check also made to make sure the symlink data does not
+ * point to an existing file.
+ *
+ * return 0 if ok else -1.
+ */
+static int
+fs_reparse_mark(char *target, vattr_t *vap, xvattr_t *xvattr)
+{
+ xoptattr_t *xoap;
+
+ if ((!target) || (!vap) || (!xvattr))
+ return (-1);
+
+ /* validate reparse string */
+ if (reparse_validate((const char *)target))
+ return (-1);
+
+ xva_init(xvattr);
+ xvattr->xva_vattr = *vap;
+ xvattr->xva_vattr.va_mask |= AT_XVATTR;
+ xoap = xva_getxoptattr(xvattr);
+ ASSERT(xoap);
+ XVA_SET_REQ(xvattr, XAT_REPARSE);
+ xoap->xoa_reparse = 1;
+
+ return (0);
+}
diff --git a/usr/src/uts/common/fs/xattr.c b/usr/src/uts/common/fs/xattr.c
index 274c57869c..137379ecc3 100644
--- a/usr/src/uts/common/fs/xattr.c
+++ b/usr/src/uts/common/fs/xattr.c
@@ -212,6 +212,9 @@ xattr_fill_nvlist(vnode_t *vp, xattr_view_t xattr_view, nvlist_t *nvlp,
VERIFY(nvlist_add_uint64(nvlp, attr_to_name(attr),
fsid) == 0);
break;
+ case F_REPARSE:
+ XVA_SET_REQ(&xvattr, XAT_REPARSE);
+ break;
default:
break;
}
@@ -294,6 +297,11 @@ xattr_fill_nvlist(vnode_t *vp, xattr_view_t xattr_view, nvlist_t *nvlp,
sizeof (xoap->xoa_createtime) /
sizeof (uint64_t)) == 0);
}
+ if (XVA_ISSET_RTN(&xvattr, XAT_REPARSE)) {
+ VERIFY(nvlist_add_boolean_value(nvlp,
+ attr_to_name(F_REPARSE),
+ xoap->xoa_reparse) == 0);
+ }
}
/*
* Check for optional ownersid/groupsid
@@ -667,6 +675,10 @@ xattr_file_write(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
return (EINVAL);
}
break;
+ case F_REPARSE:
+ XVA_SET_REQ(&xvattr, XAT_REPARSE);
+ xoap->xoa_reparse = value;
+ break;
default:
break;
}
@@ -807,6 +819,7 @@ xattr_copy(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED);
XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED);
XVA_SET_REQ(&xvattr, XAT_CREATETIME);
+ XVA_SET_REQ(&xvattr, XAT_REPARSE);
pdvp = gfs_file_parent(sdvp);
error = VOP_GETATTR(pdvp, &xvattr.xva_vattr, 0, cr, ct);
diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_znode.h b/usr/src/uts/common/fs/zfs/sys/zfs_znode.h
index 5db5b8d518..ca826abbac 100644
--- a/usr/src/uts/common/fs/zfs/sys/zfs_znode.h
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_znode.h
@@ -57,6 +57,7 @@ extern "C" {
#define ZFS_OPAQUE 0x0000010000000000
#define ZFS_AV_QUARANTINED 0x0000020000000000
#define ZFS_AV_MODIFIED 0x0000040000000000
+#define ZFS_REPARSE 0x0000080000000000
#define ZFS_ATTR_SET(zp, attr, value) \
{ \
diff --git a/usr/src/uts/common/fs/zfs/zfs_log.c b/usr/src/uts/common/fs/zfs/zfs_log.c
index 4df7115f58..f0a713ed94 100644
--- a/usr/src/uts/common/fs/zfs/zfs_log.c
+++ b/usr/src/uts/common/fs/zfs/zfs_log.c
@@ -175,6 +175,9 @@ zfs_log_xvattr(lr_attr_t *lrattr, xvattr_t *xvap)
ZFS_TIME_ENCODE(&xoap->xoa_createtime, crtime);
if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP))
bcopy(xoap->xoa_av_scanstamp, scanstamp, AV_SCANSTAMP_SZ);
+ if (XVA_ISSET_REQ(xvap, XAT_REPARSE))
+ *attrs |= (xoap->xoa_reparse == 0) ? 0 :
+ XAT0_REPARSE;
}
static void *
diff --git a/usr/src/uts/common/fs/zfs/zfs_replay.c b/usr/src/uts/common/fs/zfs/zfs_replay.c
index 85b79703a7..232422b0f8 100644
--- a/usr/src/uts/common/fs/zfs/zfs_replay.c
+++ b/usr/src/uts/common/fs/zfs/zfs_replay.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
@@ -129,6 +127,8 @@ zfs_replay_xvattr(lr_attr_t *lrattr, xvattr_t *xvap)
ZFS_TIME_DECODE(&xoap->xoa_createtime, crtime);
if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP))
bcopy(scanstamp, xoap->xoa_av_scanstamp, AV_SCANSTAMP_SZ);
+ if (XVA_ISSET_REQ(xvap, XAT_REPARSE))
+ xoap->xoa_reparse = ((*attrs & XAT0_REPARSE) != 0);
}
static int
diff --git a/usr/src/uts/common/fs/zfs/zfs_vfsops.c b/usr/src/uts/common/fs/zfs/zfs_vfsops.c
index 8f51a0dbf2..7a6b850d1c 100644
--- a/usr/src/uts/common/fs/zfs/zfs_vfsops.c
+++ b/usr/src/uts/common/fs/zfs/zfs_vfsops.c
@@ -1049,6 +1049,7 @@ zfs_set_fuid_feature(zfsvfs_t *zfsvfs)
vfs_set_feature(zfsvfs->z_vfs, VFSFT_ACEMASKONACCESS);
vfs_set_feature(zfsvfs->z_vfs, VFSFT_ACLONCREATE);
vfs_set_feature(zfsvfs->z_vfs, VFSFT_ACCESS_FILTER);
+ vfs_set_feature(zfsvfs->z_vfs, VFSFT_REPARSE);
}
}
diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c
index 644b2dba9a..6513640437 100644
--- a/usr/src/uts/common/fs/zfs/zfs_vnops.c
+++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c
@@ -2370,6 +2370,12 @@ zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
ZFS_TIME_DECODE(&xoap->xoa_createtime, pzp->zp_crtime);
XVA_SET_RTN(xvap, XAT_CREATETIME);
}
+
+ if (XVA_ISSET_REQ(xvap, XAT_REPARSE)) {
+ xoap->xoa_reparse =
+ ((pzp->zp_flags & ZFS_REPARSE) != 0);
+ XVA_SET_RTN(xvap, XAT_REPARSE);
+ }
}
ZFS_TIME_DECODE(&vap->va_atime, pzp->zp_atime);
@@ -2671,6 +2677,12 @@ top:
}
}
+ if (XVA_ISSET_REQ(xvap, XAT_REPARSE)) {
+ mutex_exit(&zp->z_lock);
+ ZFS_EXIT(zfsvfs);
+ return (EPERM);
+ }
+
if (need_policy == FALSE &&
(XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP) ||
XVA_ISSET_REQ(xvap, XAT_OPAQUE))) {
diff --git a/usr/src/uts/common/fs/zfs/zfs_znode.c b/usr/src/uts/common/fs/zfs/zfs_znode.c
index 62156fb4f6..c861bd9936 100644
--- a/usr/src/uts/common/fs/zfs/zfs_znode.c
+++ b/usr/src/uts/common/fs/zfs/zfs_znode.c
@@ -909,6 +909,10 @@ zfs_xvattr_set(znode_t *zp, xvattr_t *xvap)
zp->z_phys->zp_flags |= ZFS_BONUS_SCANSTAMP;
XVA_SET_RTN(xvap, XAT_AV_SCANSTAMP);
}
+ if (XVA_ISSET_REQ(xvap, XAT_REPARSE)) {
+ ZFS_ATTR_SET(zp, ZFS_REPARSE, xoap->xoa_reparse);
+ XVA_SET_RTN(xvap, XAT_REPARSE);
+ }
}
int
diff --git a/usr/src/uts/common/fs/zut/zut.c b/usr/src/uts/common/fs/zut/zut.c
index 9381b69aea..c655585968 100644
--- a/usr/src/uts/common/fs/zut/zut.c
+++ b/usr/src/uts/common/fs/zut/zut.c
@@ -217,6 +217,7 @@ zut_stat64(vnode_t *vp, struct stat64 *sb, uint64_t *xvs, int flag, cred_t *cr)
XVA_SET_REQ(&xv, XAT_OPAQUE);
XVA_SET_REQ(&xv, XAT_AV_QUARANTINED);
XVA_SET_REQ(&xv, XAT_AV_MODIFIED);
+ XVA_SET_REQ(&xv, XAT_REPARSE);
xv.xva_vattr.va_mask |= AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE;
if (error = VOP_GETATTR(vp, &xv.xva_vattr, flag, cr, NULL))
@@ -263,6 +264,8 @@ zut_stat64(vnode_t *vp, struct stat64 *sb, uint64_t *xvs, int flag, cred_t *cr)
*xvs |= (1 << F_AV_QUARANTINED);
if (XVA_ISSET_RTN(&xv, XAT_AV_MODIFIED) && xoap->xoa_av_modified)
*xvs |= (1 << F_AV_MODIFIED);
+ if (XVA_ISSET_RTN(&xv, XAT_REPARSE) && xoap->xoa_reparse)
+ *xvs |= (1 << F_REPARSE);
return (0);
}
diff --git a/usr/src/uts/common/sys/attr.h b/usr/src/uts/common/sys/attr.h
index 86c4cd5d6c..b312b5a429 100644
--- a/usr/src/uts/common/sys/attr.h
+++ b/usr/src/uts/common/sys/attr.h
@@ -19,15 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_ATTR_H
#define _SYS_ATTR_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -56,6 +54,7 @@ extern "C" {
#define A_AV_SCANSTAMP "av_scanstamp"
#define A_OWNERSID "ownersid"
#define A_GROUPSID "groupsid"
+#define A_REPARSE_POINT "reparse"
/* Attribute option for utilities */
#define O_HIDDEN "H"
@@ -68,6 +67,7 @@ extern "C" {
#define O_NODUMP "d"
#define O_AV_QUARANTINED "q"
#define O_AV_MODIFIED "m"
+#define O_REPARSE_POINT "r"
#define O_NONE ""
/* ownersid and groupsid are composed of two nvpairs */
@@ -92,6 +92,7 @@ typedef enum {
F_OWNERSID,
F_GROUPSID,
F_FSID,
+ F_REPARSE,
F_ATTR_ALL
} f_attr_t;
diff --git a/usr/src/uts/common/sys/vfs.h b/usr/src/uts/common/sys/vfs.h
index 17ee536024..4d0d6d1257 100644
--- a/usr/src/uts/common/sys/vfs.h
+++ b/usr/src/uts/common/sys/vfs.h
@@ -297,6 +297,7 @@ typedef uint64_t vfs_feature_t;
#define VFSFT_ACEMASKONACCESS 0x100000020 /* Can use ACEMASK for access */
#define VFSFT_SYSATTR_VIEWS 0x100000040 /* Supports sysattr view i/f */
#define VFSFT_ACCESS_FILTER 0x100000080 /* dirents filtered by access */
+#define VFSFT_REPARSE 0x100000100 /* Supports reparse point */
/*
* Argument structure for mount(2).
diff --git a/usr/src/uts/common/sys/vnode.h b/usr/src/uts/common/sys/vnode.h
index f3e3fe6879..a060c30434 100644
--- a/usr/src/uts/common/sys/vnode.h
+++ b/usr/src/uts/common/sys/vnode.h
@@ -387,6 +387,7 @@ typedef struct xoptattr {
uint8_t xoa_av_quarantined;
uint8_t xoa_av_modified;
uint8_t xoa_av_scanstamp[AV_SCANSTAMP_SZ];
+ uint8_t xoa_reparse;
} xoptattr_t;
/*
@@ -565,11 +566,12 @@ typedef vattr_t vattr32_t;
#define XAT0_AV_QUARANTINED 0x00000400 /* anti-virus quarantine */
#define XAT0_AV_MODIFIED 0x00000800 /* anti-virus modified */
#define XAT0_AV_SCANSTAMP 0x00001000 /* anti-virus scanstamp */
+#define XAT0_REPARSE 0x00002000 /* FS reparse point */
#define XAT0_ALL_ATTRS (XAT0_CREATETIME|XAT0_ARCHIVE|XAT0_SYSTEM| \
XAT0_READONLY|XAT0_HIDDEN|XAT0_NOUNLINK|XAT0_IMMUTABLE|XAT0_APPENDONLY| \
XAT0_NODUMP|XAT0_OPAQUE|XAT0_AV_QUARANTINED| \
- XAT0_AV_MODIFIED|XAT0_AV_SCANSTAMP)
+ XAT0_AV_MODIFIED|XAT0_AV_SCANSTAMP|XAT0_REPARSE)
/* Support for XAT_* optional attributes */
#define XVA_MASK 0xffffffff /* Used to mask off 32 bits */
@@ -602,6 +604,7 @@ typedef vattr_t vattr32_t;
#define XAT_AV_QUARANTINED ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_QUARANTINED)
#define XAT_AV_MODIFIED ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_MODIFIED)
#define XAT_AV_SCANSTAMP ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_SCANSTAMP)
+#define XAT_REPARSE ((XAT0_INDEX << XVA_SHFT) | XAT0_REPARSE)
/*
* The returned attribute map array (xva_rtnattrmap[]) is located past the
@@ -1274,6 +1277,9 @@ void xattr_init(void); /* Initialize vnodeops for xattrs */
/* GFS tunnel for xattrs */
int xattr_dir_lookup(vnode_t *, vnode_t **, int, cred_t *);
+/* Reparse Point */
+void reparse_point_init(void);
+
/* Context identification */
u_longlong_t fs_new_caller_id();