summaryrefslogtreecommitdiff
path: root/usr
diff options
context:
space:
mode:
authorck153898 <none@none>2007-12-10 12:25:48 -0800
committerck153898 <none@none>2007-12-10 12:25:48 -0800
commitb38f097029665f4ece801ca129913d36f757b49c (patch)
tree5ed7f4d7fb0fdae99be722118762b9249191a3d4 /usr
parent423908e1eda59d79f1f867966cafecd54cfaa635 (diff)
downloadillumos-gate-b38f097029665f4ece801ca129913d36f757b49c.tar.gz
6627223 gfs needs to support extended dirent flags
Diffstat (limited to 'usr')
-rw-r--r--usr/src/uts/common/fs/ctfs/ctfs_all.c17
-rw-r--r--usr/src/uts/common/fs/ctfs/ctfs_tdir.c17
-rw-r--r--usr/src/uts/common/fs/gfs.c136
-rw-r--r--usr/src/uts/common/fs/objfs/objfs_root.c19
-rw-r--r--usr/src/uts/common/fs/proc/prvnops.c31
-rw-r--r--usr/src/uts/common/fs/xattr.c96
-rw-r--r--usr/src/uts/common/fs/zfs/dmu_objset.c4
-rw-r--r--usr/src/uts/common/fs/zfs/sys/dmu.h2
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_ctldir.c32
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_ioctl.c2
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_vnops.c17
-rw-r--r--usr/src/uts/common/sys/attr.h1
-rw-r--r--usr/src/uts/common/sys/gfs.h16
13 files changed, 299 insertions, 91 deletions
diff --git a/usr/src/uts/common/fs/ctfs/ctfs_all.c b/usr/src/uts/common/fs/ctfs/ctfs_all.c
index 6a0d080e56..8a9e029d68 100644
--- a/usr/src/uts/common/fs/ctfs/ctfs_all.c
+++ b/usr/src/uts/common/fs/ctfs/ctfs_all.c
@@ -48,8 +48,8 @@
* CTFS routines for the /system/contract/all vnode.
*/
-static int ctfs_adir_do_readdir(vnode_t *, struct dirent64 *, int *, offset_t *,
- offset_t *, void *);
+static int ctfs_adir_do_readdir(vnode_t *, void *, int *, offset_t *,
+ offset_t *, void *, int);
static int ctfs_adir_do_lookup(vnode_t *, const char *, vnode_t **, ino64_t *,
cred_t *);
@@ -120,11 +120,16 @@ ctfs_adir_do_lookup(vnode_t *vp, const char *nm, vnode_t **vpp, ino64_t *inop,
/* ARGSUSED */
static int
-ctfs_adir_do_readdir(vnode_t *vp, struct dirent64 *dp, int *eofp,
- offset_t *offp, offset_t *nextp, void *unused)
+ctfs_adir_do_readdir(vnode_t *vp, void *dp, int *eofp,
+ offset_t *offp, offset_t *nextp, void *unused, int flags)
{
uint64_t zuniqid;
ctid_t next;
+ struct dirent64 *odp = dp;
+
+ /* ctfs does not support V_RDDIR_ENTFLAGS */
+ if (flags & V_RDDIR_ENTFLAGS)
+ return (ENOTSUP);
zuniqid = VTOZONE(vp)->zone_uniqid;
next = contract_lookup(zuniqid, *offp);
@@ -134,8 +139,8 @@ ctfs_adir_do_readdir(vnode_t *vp, struct dirent64 *dp, int *eofp,
return (0);
}
- dp->d_ino = CTFS_INO_CT_LINK(next);
- numtos(next, dp->d_name);
+ odp->d_ino = CTFS_INO_CT_LINK(next);
+ numtos(next, odp->d_name);
*offp = next;
*nextp = next + 1;
diff --git a/usr/src/uts/common/fs/ctfs/ctfs_tdir.c b/usr/src/uts/common/fs/ctfs/ctfs_tdir.c
index fd3c229c0f..ce83fa5097 100644
--- a/usr/src/uts/common/fs/ctfs/ctfs_tdir.c
+++ b/usr/src/uts/common/fs/ctfs/ctfs_tdir.c
@@ -56,8 +56,8 @@ static gfs_dirent_t ctfs_tdir_dirents[] = {
};
#define CTFS_NSPECIALS ((sizeof ctfs_tdir_dirents / sizeof (gfs_dirent_t)) - 1)
-static int ctfs_tdir_do_readdir(vnode_t *, struct dirent64 *, int *, offset_t *,
- offset_t *, void *);
+static int ctfs_tdir_do_readdir(vnode_t *, void *, int *, offset_t *,
+ offset_t *, void *, int);
static int ctfs_tdir_do_lookup(vnode_t *, const char *, vnode_t **, ino64_t *,
cred_t *);
static ino64_t ctfs_tdir_do_inode(vnode_t *, int);
@@ -107,12 +107,17 @@ ctfs_tdir_do_inode(vnode_t *vp, int index)
/* ARGSUSED */
static int
-ctfs_tdir_do_readdir(vnode_t *vp, struct dirent64 *dp, int *eofp,
- offset_t *offp, offset_t *nextp, void *data)
+ctfs_tdir_do_readdir(vnode_t *vp, void *dp, int *eofp,
+ offset_t *offp, offset_t *nextp, void *data, int flags)
{
uint64_t zuniqid;
ctid_t next;
ct_type_t *ty = ct_types[gfs_file_index(vp)];
+ struct dirent64 *odp = dp;
+
+ /* ctfs does not support V_RDDIR_ENTFLAGS */
+ if (flags & V_RDDIR_ENTFLAGS)
+ return (ENOTSUP);
zuniqid = VTOZONE(vp)->zone_uniqid;
next = contract_type_lookup(ty, zuniqid, *offp);
@@ -122,8 +127,8 @@ ctfs_tdir_do_readdir(vnode_t *vp, struct dirent64 *dp, int *eofp,
return (0);
}
- dp->d_ino = CTFS_INO_CT_DIR(next);
- numtos(next, dp->d_name);
+ odp->d_ino = CTFS_INO_CT_DIR(next);
+ numtos(next, odp->d_name);
*offp = next;
*nextp = next + 1;
diff --git a/usr/src/uts/common/fs/gfs.c b/usr/src/uts/common/fs/gfs.c
index 24f2ad2a7a..c56fb004f0 100644
--- a/usr/src/uts/common/fs/gfs.c
+++ b/usr/src/uts/common/fs/gfs.c
@@ -152,6 +152,38 @@ gfs_make_opsvec(gfs_opsvec_t *vec)
*/
/*
+ * gfs_get_parent_ino: used to obtain a parent inode number and the
+ * inode number of the given vnode in preparation for calling gfs_readdir_init.
+ */
+int
+gfs_get_parent_ino(vnode_t *dvp, cred_t *cr, caller_context_t *ct,
+ ino64_t *pino, ino64_t *ino)
+{
+ vnode_t *parent;
+ gfs_dir_t *dp = dvp->v_data;
+ int error;
+
+ *ino = dp->gfsd_file.gfs_ino;
+ parent = dp->gfsd_file.gfs_parent;
+
+ if (parent == NULL) {
+ *pino = *ino; /* root of filesystem */
+ } else if (dvp->v_flag & V_XATTRDIR) {
+ vattr_t va;
+
+ va.va_mask = AT_NODEID;
+ error = VOP_GETATTR(parent, &va, 0, cr, ct);
+ if (error)
+ return (error);
+ *pino = va.va_nodeid;
+ } else {
+ *pino = ((gfs_file_t *)(parent->v_data))->gfs_ino;
+ }
+
+ return (0);
+}
+
+/*
* gfs_readdir_init: initiate a generic readdir
* st - a pointer to an uninitialized gfs_readdir_state_t structure
* name_max - the directory's maximum file name length
@@ -159,6 +191,7 @@ gfs_make_opsvec(gfs_opsvec_t *vec)
* uiop - the uiop passed to readdir
* parent - the parent directory's inode
* self - this directory's inode
+ * flags - flags from VOP_READDIR
*
* Returns 0 or a non-zero errno.
*
@@ -189,8 +222,10 @@ gfs_make_opsvec(gfs_opsvec_t *vec)
*/
int
gfs_readdir_init(gfs_readdir_state_t *st, int name_max, int ureclen,
- uio_t *uiop, ino64_t parent, ino64_t self)
+ uio_t *uiop, ino64_t parent, ino64_t self, int flags)
{
+ size_t dirent_size;
+
if (uiop->uio_loffset < 0 || uiop->uio_resid <= 0 ||
(uiop->uio_loffset % ureclen) != 0)
return (EINVAL);
@@ -198,9 +233,14 @@ gfs_readdir_init(gfs_readdir_state_t *st, int name_max, int ureclen,
st->grd_ureclen = ureclen;
st->grd_oresid = uiop->uio_resid;
st->grd_namlen = name_max;
- st->grd_dirent = kmem_zalloc(DIRENT64_RECLEN(st->grd_namlen), KM_SLEEP);
+ if (flags & V_RDDIR_ENTFLAGS)
+ dirent_size = EDIRENT_RECLEN(st->grd_namlen);
+ else
+ dirent_size = DIRENT64_RECLEN(st->grd_namlen);
+ st->grd_dirent = kmem_zalloc(dirent_size, KM_SLEEP);
st->grd_parent = parent;
st->grd_self = self;
+ st->grd_flags = flags;
return (0);
}
@@ -208,8 +248,8 @@ gfs_readdir_init(gfs_readdir_state_t *st, int name_max, int ureclen,
/*
* gfs_readdir_emit_int: internal routine to emit directory entry
*
- * st - the current readdir state, which must have d_ino and d_name
- * set
+ * st - the current readdir state, which must have d_ino/ed_ino
+ * and d_name/ed_name set
* uiop - caller-supplied uio pointer
* next - the offset of the next entry
*/
@@ -217,8 +257,16 @@ static int
gfs_readdir_emit_int(gfs_readdir_state_t *st, uio_t *uiop, offset_t next)
{
int reclen;
+ dirent64_t *dp;
+ edirent_t *edp;
- reclen = DIRENT64_RECLEN(strlen(st->grd_dirent->d_name));
+ if (st->grd_flags & V_RDDIR_ENTFLAGS) {
+ edp = st->grd_dirent;
+ reclen = EDIRENT_RECLEN(strlen(edp->ed_name));
+ } else {
+ dp = st->grd_dirent;
+ reclen = DIRENT64_RECLEN(strlen(dp->d_name));
+ }
if (reclen > uiop->uio_resid) {
/*
@@ -229,8 +277,13 @@ gfs_readdir_emit_int(gfs_readdir_state_t *st, uio_t *uiop, offset_t next)
return (-1);
}
- st->grd_dirent->d_off = next;
- st->grd_dirent->d_reclen = (ushort_t)reclen;
+ if (st->grd_flags & V_RDDIR_ENTFLAGS) {
+ edp->ed_off = next;
+ edp->ed_reclen = (ushort_t)reclen;
+ } else {
+ dp->d_off = next;
+ dp->d_reclen = (ushort_t)reclen;
+ }
if (uiomove((caddr_t)st->grd_dirent, reclen, UIO_READ, uiop))
return (EFAULT);
@@ -245,6 +298,7 @@ gfs_readdir_emit_int(gfs_readdir_state_t *st, uio_t *uiop, offset_t next)
* voff - the virtual offset (obtained from gfs_readdir_pred)
* ino - the entry's inode
* name - the entry's name
+ * eflags - value for ed_eflags (if processing edirent_t)
*
* Returns a 0 on success, a non-zero errno on failure, or -1 if the
* readdir loop should terminate. A non-zero result (either errno or
@@ -253,12 +307,22 @@ gfs_readdir_emit_int(gfs_readdir_state_t *st, uio_t *uiop, offset_t next)
*/
int
gfs_readdir_emit(gfs_readdir_state_t *st, uio_t *uiop, offset_t voff,
- ino64_t ino, const char *name)
+ ino64_t ino, const char *name, int eflags)
{
offset_t off = (voff + 2) * st->grd_ureclen;
- st->grd_dirent->d_ino = ino;
- (void) strncpy(st->grd_dirent->d_name, name, st->grd_namlen);
+ if (st->grd_flags & V_RDDIR_ENTFLAGS) {
+ edirent_t *edp = st->grd_dirent;
+
+ edp->ed_ino = ino;
+ (void) strncpy(edp->ed_name, name, st->grd_namlen);
+ edp->ed_eflags = eflags;
+ } else {
+ dirent64_t *dp = st->grd_dirent;
+
+ dp->d_ino = ino;
+ (void) strncpy(dp->d_name, name, st->grd_namlen);
+ }
/*
* Inter-entry offsets are invalid, so we assume a record size of
@@ -278,7 +342,7 @@ gfs_readdir_emitn(gfs_readdir_state_t *st, uio_t *uiop, offset_t voff,
char buf[40];
numtos(num, buf);
- return (gfs_readdir_emit(st, uiop, voff, ino, buf));
+ return (gfs_readdir_emit(st, uiop, voff, ino, buf, 0));
}
/*
@@ -304,11 +368,11 @@ top:
voff = off - 2;
if (off == 0) {
if ((error = gfs_readdir_emit(st, uiop, voff, st->grd_self,
- ".")) == 0)
+ ".", 0)) == 0)
goto top;
} else if (off == 1) {
if ((error = gfs_readdir_emit(st, uiop, voff, st->grd_parent,
- "..")) == 0)
+ "..", 0)) == 0)
goto top;
} else {
*voffp = voff;
@@ -330,7 +394,13 @@ top:
int
gfs_readdir_fini(gfs_readdir_state_t *st, int error, int *eofp, int eof)
{
- kmem_free(st->grd_dirent, DIRENT64_RECLEN(st->grd_namlen));
+ size_t dirent_size;
+
+ if (st->grd_flags & V_RDDIR_ENTFLAGS)
+ dirent_size = EDIRENT_RECLEN(st->grd_namlen);
+ else
+ dirent_size = DIRENT64_RECLEN(st->grd_namlen);
+ kmem_free(st->grd_dirent, dirent_size);
if (error > 0)
return (error);
if (eofp)
@@ -806,13 +876,15 @@ out:
* This is significantly more complex, thanks to the particulars of
* VOP_READDIR().
*
- * int gfs_readdir_cb(vnode_t *vp, struct dirent64 *dp, int *eofp,
- * offset_t *off, offset_t *nextoff, void *data)
+ * int gfs_readdir_cb(vnode_t *vp, void *dp, int *eofp,
+ * offset_t *off, offset_t *nextoff, void *data, int flags)
*
* vp - directory vnode
* dp - directory entry, sized according to maxlen given to
* gfs_dir_create(). callback must fill in d_name and
- * d_ino.
+ * d_ino (if a dirent64_t), or ed_name, ed_ino, and ed_eflags
+ * (if an edirent_t). edirent_t is used if V_RDDIR_ENTFLAGS
+ * is set in 'flags'.
* eofp - callback must set to 1 when EOF has been reached
* off - on entry, the last offset read from the directory. Callback
* must set to the offset of the current entry, typically left
@@ -820,38 +892,26 @@ out:
* nextoff - callback must set to offset of next entry. Typically
* (off + 1)
* data - caller-supplied data
+ * flags - VOP_READDIR flags
*
* Return 0 on success, or error on failure.
*/
int
gfs_dir_readdir(vnode_t *dvp, uio_t *uiop, int *eofp, void *data, cred_t *cr,
- caller_context_t *ct)
+ caller_context_t *ct, int flags)
{
gfs_readdir_state_t gstate;
int error, eof = 0;
ino64_t ino, pino;
offset_t off, next;
gfs_dir_t *dp = dvp->v_data;
- vnode_t *parent;
-
- ino = dp->gfsd_file.gfs_ino;
- parent = dp->gfsd_file.gfs_parent;
-
- if (parent == NULL)
- pino = ino; /* root of filesystem */
- else if (dvp->v_flag & V_XATTRDIR) {
- vattr_t va;
- va.va_mask = AT_NODEID;
- error = VOP_GETATTR(parent, &va, 0, cr, ct);
- if (error)
- return (error);
- pino = va.va_nodeid;
- } else
- pino = ((gfs_file_t *)(parent->v_data))->gfs_ino;
+ error = gfs_get_parent_ino(dvp, cr, ct, &pino, &ino);
+ if (error)
+ return (error);
if ((error = gfs_readdir_init(&gstate, dp->gfsd_maxlen, 1, uiop,
- pino, ino)) != 0)
+ pino, ino, flags)) != 0)
return (error);
while ((error = gfs_readdir_pred(&gstate, uiop, &off)) == 0 &&
@@ -861,7 +921,7 @@ gfs_dir_readdir(vnode_t *dvp, uio_t *uiop, int *eofp, void *data, cred_t *cr,
ino = dp->gfsd_inode(dvp, off);
if ((error = gfs_readdir_emit(&gstate, uiop,
- off, ino, dp->gfsd_static[off].gfse_name))
+ off, ino, dp->gfsd_static[off].gfse_name, 0))
!= 0)
break;
@@ -870,7 +930,7 @@ gfs_dir_readdir(vnode_t *dvp, uio_t *uiop, int *eofp, void *data, cred_t *cr,
if ((error = dp->gfsd_readdir(dvp,
gstate.grd_dirent, &eof, &off, &next,
- data)) != 0 || eof)
+ data, flags)) != 0 || eof)
break;
off += dp->gfsd_nstatic + 2;
@@ -918,7 +978,7 @@ int
gfs_vop_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp,
caller_context_t *ct, int flags)
{
- return (gfs_dir_readdir(vp, uiop, eofp, NULL, cr, ct));
+ return (gfs_dir_readdir(vp, uiop, eofp, NULL, cr, ct, flags));
}
diff --git a/usr/src/uts/common/fs/objfs/objfs_root.c b/usr/src/uts/common/fs/objfs/objfs_root.c
index 06f06d35f9..1b108616ca 100644
--- a/usr/src/uts/common/fs/objfs/objfs_root.c
+++ b/usr/src/uts/common/fs/objfs/objfs_root.c
@@ -40,8 +40,8 @@ extern int last_module_id;
static int objfs_root_do_lookup(vnode_t *, const char *, vnode_t **, ino64_t *,
cred_t *);
-static int objfs_root_do_readdir(vnode_t *, struct dirent64 *, int *,
- offset_t *, offset_t *, void *);
+static int objfs_root_do_readdir(vnode_t *, void *, int *,
+ offset_t *, offset_t *, void *, int);
vnode_t *
objfs_create_root(vfs_t *vfsp)
@@ -105,11 +105,16 @@ objfs_root_do_lookup(vnode_t *vp, const char *nm, vnode_t **vpp, ino64_t *inop,
/* ARGSUSED */
int
-objfs_root_do_readdir(vnode_t *vp, struct dirent64 *dp, int *eofp,
- offset_t *offp, offset_t *nextp, void *data)
+objfs_root_do_readdir(vnode_t *vp, void *dp, int *eofp,
+ offset_t *offp, offset_t *nextp, void *data, int flags)
{
struct modctl **mpp = data;
struct modctl *mp = *mpp;
+ struct dirent64 *odp = dp;
+
+ /* objfs does not support V_RDDIR_ENTFLAGS */
+ if (flags & V_RDDIR_ENTFLAGS)
+ return (ENOTSUP);
mutex_enter(&mod_lock);
@@ -142,8 +147,8 @@ objfs_root_do_readdir(vnode_t *vp, struct dirent64 *dp, int *eofp,
*/
mutex_exit(&mod_lock);
- (void) strncpy(dp->d_name, mp->mod_modname, OBJFS_NAME_MAX);
- dp->d_ino = OBJFS_INO_ODIR(mp->mod_id);
+ (void) strncpy(odp->d_name, mp->mod_modname, OBJFS_NAME_MAX);
+ odp->d_ino = OBJFS_INO_ODIR(mp->mod_id);
*offp = mp->mod_id;
*nextp = mp->mod_id + 1;
@@ -157,7 +162,7 @@ objfs_root_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp,
{
struct modctl *mp = &modules;
- return (gfs_dir_readdir(vp, uiop, eofp, &mp, cr, ct));
+ return (gfs_dir_readdir(vp, uiop, eofp, &mp, cr, ct, flags));
}
const fs_operation_def_t objfs_tops_root[] = {
diff --git a/usr/src/uts/common/fs/proc/prvnops.c b/usr/src/uts/common/fs/proc/prvnops.c
index 4b61f1cdcc..866dee6ca8 100644
--- a/usr/src/uts/common/fs/proc/prvnops.c
+++ b/usr/src/uts/common/fs/proc/prvnops.c
@@ -420,7 +420,7 @@ prclose(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
return (0);
ASSERT(type != PR_OBJECT && type != PR_FD &&
- type != PR_CURDIR && type != PR_ROOTDIR);
+ type != PR_CURDIR && type != PR_ROOTDIR);
/*
* If the process exists, lock it now.
@@ -2267,7 +2267,7 @@ pr_read_lusage_32(prnode_t *pnp, uio_t *uiop)
ASSERT(nlwp > 0);
--nlwp;
upup = (prusage32_t *)
- ((caddr_t)upup + LSPAN32(prusage32_t));
+ ((caddr_t)upup + LSPAN32(prusage32_t));
prgetusage(t, pup);
prcvtusage32(pup, upup);
}
@@ -2825,7 +2825,7 @@ prgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
vap->va_nlink = 1;
vap->va_nodeid = pnp->pr_ino? pnp->pr_ino :
- pmkino(pcp->prc_tslot, pcp->prc_slot, pnp->pr_type);
+ pmkino(pcp->prc_tslot, pcp->prc_slot, pnp->pr_type);
if ((pcp->prc_flags & PRC_LWP) && pcp->prc_tslot != -1) {
vap->va_atime.tv_sec = vap->va_mtime.tv_sec =
vap->va_ctime.tv_sec =
@@ -3519,7 +3519,7 @@ pr_lookup_piddir(vnode_t *dp, char *comp)
case PR_ROOTDIR:
up = PTOU(p);
vp = (type == PR_CURDIR)? up->u_cdir :
- (up->u_rdir? up->u_rdir : rootdir);
+ (up->u_rdir? up->u_rdir : rootdir);
if (vp == NULL) { /* can't happen? */
prunlock(dpnp);
@@ -4635,7 +4635,7 @@ pr_readdir_procdir(prnode_t *pnp, uio_t *uiop, int *eofp)
zoneid = VTOZONE(PTOV(pnp))->zone_id;
if ((error = gfs_readdir_init(&gstate, PNSIZ, PRSDSIZE, uiop,
- PRROOTINO, PRROOTINO)) != 0)
+ PRROOTINO, PRROOTINO, 0)) != 0)
return (error);
/*
@@ -4726,7 +4726,7 @@ pr_readdir_piddir(prnode_t *pnp, uio_t *uiop, int *eofp)
dirent.d_ino = PRROOTINO;
else
dirent.d_ino = pmkino(0, pnp->pr_pcommon->prc_slot,
- dirent.d_ino);
+ dirent.d_ino);
if ((error = uiomove((caddr_t)&dirent, sizeof (prdirent_t),
UIO_READ, uiop)) != 0)
return (error);
@@ -4819,9 +4819,9 @@ rebuild_objdir(struct as *as)
*/
ulong_t newsize = (nold + nnew + 0xf) & ~0xf;
vnode_t **newdir = kmem_zalloc(newsize * sizeof (vnode_t *),
- KM_SLEEP);
+ KM_SLEEP);
bcopy(as->a_objectdir, newdir,
- as->a_sizedir * sizeof (vnode_t *));
+ as->a_sizedir * sizeof (vnode_t *));
kmem_free(as->a_objectdir, as->a_sizedir * sizeof (vnode_t *));
as->a_objectdir = newdir;
as->a_sizedir = newsize;
@@ -4891,7 +4891,7 @@ pr_readdir_objectdir(prnode_t *pnp, uio_t *uiop, int *eofp)
if ((error = gfs_readdir_init(&gstate, 64, PRSDSIZE, uiop,
pmkino(0, pslot, PR_PIDDIR),
- pmkino(0, pslot, PR_OBJECTDIR))) != 0) {
+ pmkino(0, pslot, PR_OBJECTDIR), 0)) != 0) {
mutex_enter(&p->p_lock);
prunlock(pnp);
return (error);
@@ -4952,7 +4952,7 @@ pr_readdir_objectdir(prnode_t *pnp, uio_t *uiop, int *eofp)
pr_object_name(str, vp, &vattr);
error = gfs_readdir_emit(&gstate, uiop, n, vattr.va_nodeid,
- str);
+ str, 0);
if (error)
break;
@@ -4996,7 +4996,8 @@ pr_readdir_lwpdir(prnode_t *pnp, uio_t *uiop, int *eofp)
if ((error = gfs_readdir_init(&gstate, PLNSIZ, PRSDSIZE, uiop,
- pmkino(0, pslot, PR_PIDDIR), pmkino(0, pslot, PR_LWPDIR))) != 0) {
+ pmkino(0, pslot, PR_PIDDIR),
+ pmkino(0, pslot, PR_LWPDIR), 0)) != 0) {
mutex_enter(&p->p_lock);
prunlock(pnp);
return (error);
@@ -5126,7 +5127,7 @@ pr_readdir_fddir(prnode_t *pnp, uio_t *uiop, int *eofp)
mutex_exit(&p->p_lock);
if ((error = gfs_readdir_init(&gstate, PLNSIZ, PRSDSIZE, uiop,
- pmkino(0, pslot, PR_PIDDIR), pmkino(0, pslot, PR_FDDIR))) != 0) {
+ pmkino(0, pslot, PR_PIDDIR), pmkino(0, pslot, PR_FDDIR), 0)) != 0) {
mutex_enter(&p->p_lock);
prunlock(pnp);
return (error);
@@ -5353,7 +5354,7 @@ pr_readdir_tmpldir(prnode_t *pnp, uio_t *uiop, int *eofp)
if ((error = gfs_readdir_init(&gstate, PRDIRSIZE, PRSDSIZE, uiop,
pmkino(tslot, pslot, PR_LWPDIR),
- pmkino(tslot, pslot, PR_TMPLDIR))) != 0) {
+ pmkino(tslot, pslot, PR_TMPLDIR), 0)) != 0) {
mutex_enter(&p->p_lock);
prunlock(pnp);
return (error);
@@ -5382,7 +5383,7 @@ pr_readdir_tmpldir(prnode_t *pnp, uio_t *uiop, int *eofp)
ASSERT(ct_ntypes <= 4);
error = gfs_readdir_emit(&gstate, uiop, n,
pmkino((tslot << 2) | n, pslot, PR_TMPL),
- ct_types[n]->ct_type_name);
+ ct_types[n]->ct_type_name, 0);
if (error)
break;
}
@@ -5412,7 +5413,7 @@ pr_readdir_ctdir(prnode_t *pnp, uio_t *uiop, int *eofp)
mutex_exit(&p->p_lock);
if ((error = gfs_readdir_init(&gstate, PRDIRSIZE, PRSDSIZE, uiop,
- pmkino(0, pslot, PR_PIDDIR), pmkino(0, pslot, PR_CTDIR))) != 0) {
+ pmkino(0, pslot, PR_PIDDIR), pmkino(0, pslot, PR_CTDIR), 0)) != 0) {
mutex_enter(&p->p_lock);
prunlock(pnp);
return (error);
diff --git a/usr/src/uts/common/fs/xattr.c b/usr/src/uts/common/fs/xattr.c
index 65e0cd80d0..7d30b1965d 100644
--- a/usr/src/uts/common/fs/xattr.c
+++ b/usr/src/uts/common/fs/xattr.c
@@ -769,6 +769,22 @@ is_sattr_name(char *s)
return (0);
}
+/*
+ * Given the name of an extended attribute file, determine if there is a
+ * normalization conflict with a sysattr view name.
+ */
+int
+xattr_sysattr_casechk(char *s)
+{
+ int i;
+
+ for (i = 0; i < XATTRDIR_NENTS; ++i) {
+ if (strcasecmp(s, xattr_dirents[i].gfse_name) == 0)
+ return (1);
+ }
+ return (0);
+}
+
static int
xattr_copy(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
cred_t *cr, caller_context_t *ct)
@@ -1075,6 +1091,37 @@ xattr_dir_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
return (error);
}
+/*
+ * readdir_xattr_casecmp: given a system attribute name, see if there
+ * is a real xattr with the same normalized name.
+ */
+static int
+readdir_xattr_casecmp(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
+ int *eflags)
+{
+ int error;
+ vnode_t *vp;
+ struct pathname pn;
+ int flags = FIGNORECASE;
+
+ *eflags = 0;
+
+ error = pn_get(nm, UIO_SYSSPACE, &pn);
+ if (error == 0) {
+ error = VOP_LOOKUP(dvp, nm, &vp, &pn, LOOKUP_XATTR, rootvp,
+ cr, ct, &flags, NULL);
+ if (error == 0) {
+ *eflags = ED_CASE_CONFLICT;
+ VN_RELE(vp);
+ } else if (error == ENOENT) {
+ error = 0;
+ }
+ pn_free(&pn);
+ }
+
+ return (error);
+}
+
static int
xattr_dir_readdir(vnode_t *dvp, uio_t *uiop, cred_t *cr, int *eofp,
caller_context_t *ct, int flags)
@@ -1101,6 +1148,11 @@ xattr_dir_readdir(vnode_t *dvp, uio_t *uiop, cred_t *cr, int *eofp,
* Start by reading up the static entries.
*/
if (uiop->uio_loffset == 0) {
+ ino64_t pino, ino;
+ offset_t off;
+ gfs_dir_t *dp = dvp->v_data;
+ gfs_readdir_state_t gstate;
+
if (has_xattrs) {
/*
* If there is a real xattr dir, skip . and ..
@@ -1109,13 +1161,53 @@ xattr_dir_readdir(vnode_t *dvp, uio_t *uiop, cred_t *cr, int *eofp,
*/
uiop->uio_loffset = GFS_STATIC_ENTRY_OFFSET;
}
- error = gfs_dir_readdir(dvp, uiop, eofp, NULL, cr, ct);
+ error = gfs_get_parent_ino(dvp, cr, ct, &pino, &ino);
+ if (error == 0) {
+ error = gfs_readdir_init(&gstate, dp->gfsd_maxlen, 1,
+ uiop, pino, ino, flags);
+ }
if (error) {
- if (has_xattrs) {
+ if (has_xattrs)
VN_RELE(pvp);
+ return (error);
+ }
+
+ while ((error = gfs_readdir_pred(&gstate, uiop, &off)) == 0 &&
+ !*eofp) {
+ if (off >= 0 && off < dp->gfsd_nstatic) {
+ int eflags = 0;
+
+ /*
+ * Check to see if this sysattr set name has a
+ * case-insensitive conflict with a real xattr
+ * name.
+ */
+ if ((flags & V_RDDIR_ENTFLAGS) && has_xattrs) {
+ error = readdir_xattr_casecmp(pvp,
+ dp->gfsd_static[off].gfse_name,
+ cr, ct, &eflags);
+ if (error)
+ break;
+ }
+ ino = dp->gfsd_inode(dvp, off);
+
+ error = gfs_readdir_emit(&gstate, uiop, off,
+ ino, dp->gfsd_static[off].gfse_name,
+ eflags);
+ if (error)
+ break;
+ } else {
+ *eofp = 1;
}
+ }
+
+ error = gfs_readdir_fini(&gstate, error, eofp, *eofp);
+ if (error) {
+ if (has_xattrs)
+ VN_RELE(pvp);
return (error);
}
+
/*
* We must read all of the static entries in the first
* call. Otherwise we won't know if uio_loffset in a
diff --git a/usr/src/uts/common/fs/zfs/dmu_objset.c b/usr/src/uts/common/fs/zfs/dmu_objset.c
index 5b1d25add6..7e6b8dbaca 100644
--- a/usr/src/uts/common/fs/zfs/dmu_objset.c
+++ b/usr/src/uts/common/fs/zfs/dmu_objset.c
@@ -946,7 +946,7 @@ dmu_objset_is_snapshot(objset_t *os)
int
dmu_snapshot_list_next(objset_t *os, int namelen, char *name,
- uint64_t *idp, uint64_t *offp)
+ uint64_t *idp, uint64_t *offp, boolean_t *case_conflict)
{
dsl_dataset_t *ds = os->os->os_dsl_dataset;
zap_cursor_t cursor;
@@ -972,6 +972,8 @@ dmu_snapshot_list_next(objset_t *os, int namelen, char *name,
(void) strcpy(name, attr.za_name);
if (idp)
*idp = attr.za_first_integer;
+ if (case_conflict)
+ *case_conflict = attr.za_normalization_conflict;
zap_cursor_advance(&cursor);
*offp = zap_cursor_serialize(&cursor);
zap_cursor_fini(&cursor);
diff --git a/usr/src/uts/common/fs/zfs/sys/dmu.h b/usr/src/uts/common/fs/zfs/sys/dmu.h
index f59aadf50a..216a906984 100644
--- a/usr/src/uts/common/fs/zfs/sys/dmu.h
+++ b/usr/src/uts/common/fs/zfs/sys/dmu.h
@@ -539,7 +539,7 @@ extern void dmu_objset_name(objset_t *os, char *buf);
extern dmu_objset_type_t dmu_objset_type(objset_t *os);
extern uint64_t dmu_objset_id(objset_t *os);
extern int dmu_snapshot_list_next(objset_t *os, int namelen, char *name,
- uint64_t *id, uint64_t *offp);
+ uint64_t *id, uint64_t *offp, boolean_t *case_conflict);
extern int dmu_dir_list_next(objset_t *os, int namelen, char *name,
uint64_t *idp, uint64_t *offp);
extern void dmu_objset_set_user(objset_t *os, void *user_ptr);
diff --git a/usr/src/uts/common/fs/zfs/zfs_ctldir.c b/usr/src/uts/common/fs/zfs/zfs_ctldir.c
index b272d16ddb..6a3bc4a4c2 100644
--- a/usr/src/uts/common/fs/zfs/zfs_ctldir.c
+++ b/usr/src/uts/common/fs/zfs/zfs_ctldir.c
@@ -780,25 +780,41 @@ domount:
/* ARGSUSED */
static int
-zfsctl_snapdir_readdir_cb(vnode_t *vp, struct dirent64 *dp, int *eofp,
- offset_t *offp, offset_t *nextp, void *data)
+zfsctl_snapdir_readdir_cb(vnode_t *vp, void *dp, int *eofp,
+ offset_t *offp, offset_t *nextp, void *data, int flags)
{
zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
char snapname[MAXNAMELEN];
uint64_t id, cookie;
+ boolean_t case_conflict;
+ int error;
ZFS_ENTER(zfsvfs);
cookie = *offp;
- if (dmu_snapshot_list_next(zfsvfs->z_os, MAXNAMELEN, snapname, &id,
- &cookie) == ENOENT) {
- *eofp = 1;
+ error = dmu_snapshot_list_next(zfsvfs->z_os, MAXNAMELEN, snapname, &id,
+ &cookie, &case_conflict);
+ if (error) {
ZFS_EXIT(zfsvfs);
- return (0);
+ if (error == ENOENT) {
+ *eofp = 1;
+ return (0);
+ }
+ return (error);
}
- (void) strcpy(dp->d_name, snapname);
- dp->d_ino = ZFSCTL_INO_SNAP(id);
+ if (flags & V_RDDIR_ENTFLAGS) {
+ edirent_t *eodp = dp;
+
+ (void) strcpy(eodp->ed_name, snapname);
+ eodp->ed_ino = ZFSCTL_INO_SNAP(id);
+ eodp->ed_eflags = case_conflict ? ED_CASE_CONFLICT : 0;
+ } else {
+ struct dirent64 *odp = dp;
+
+ (void) strcpy(odp->d_name, snapname);
+ odp->d_ino = ZFSCTL_INO_SNAP(id);
+ }
*nextp = cookie;
ZFS_EXIT(zfsvfs);
diff --git a/usr/src/uts/common/fs/zfs/zfs_ioctl.c b/usr/src/uts/common/fs/zfs/zfs_ioctl.c
index 31875cd8e2..11058a86ad 100644
--- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c
+++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c
@@ -1309,7 +1309,7 @@ zfs_ioc_snapshot_list_next(zfs_cmd_t *zc)
error = dmu_snapshot_list_next(os,
sizeof (zc->zc_name) - strlen(zc->zc_name),
- zc->zc_name + strlen(zc->zc_name), NULL, &zc->zc_cookie);
+ zc->zc_name + strlen(zc->zc_name), NULL, &zc->zc_cookie, NULL);
if (error == ENOENT)
error = ESRCH;
diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c
index 21c57c2027..011b62a79d 100644
--- a/usr/src/uts/common/fs/zfs/zfs_vnops.c
+++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c
@@ -73,6 +73,7 @@
#include <sys/extdirent.h>
#include <sys/kidmap.h>
#include <sys/cred_impl.h>
+#include <sys/attr.h>
/*
* Programming rules.
@@ -1861,6 +1862,7 @@ zfs_readdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
int outcount;
int error;
uint8_t prefetch;
+ boolean_t check_sysattrs;
ZFS_ENTER(zfsvfs);
ZFS_VERIFY_ZP(zp);
@@ -1924,6 +1926,16 @@ zfs_readdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
eodp = (struct edirent *)odp;
/*
+ * If this VFS supports system attributes; and we're looking at an
+ * extended attribute directory; and we care about normalization
+ * conflicts on this vfs; then we must check for normalization
+ * conflicts with the sysattr name space.
+ */
+ check_sysattrs = vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR) &&
+ (vp->v_flag & V_XATTRDIR) && zfsvfs->z_norm &&
+ (flags & V_RDDIR_ENTFLAGS);
+
+ /*
* Transform to file-system independent format
*/
outcount = 0;
@@ -1973,6 +1985,11 @@ zfs_readdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
* MacOS X can extract the object type here such as:
* uint8_t type = ZFS_DIRENT_TYPE(zap.za_first_integer);
*/
+
+ if (check_sysattrs && !zap.za_normalization_conflict) {
+ zap.za_normalization_conflict =
+ xattr_sysattr_casechk(zap.za_name);
+ }
}
if (flags & V_RDDIR_ENTFLAGS)
diff --git a/usr/src/uts/common/sys/attr.h b/usr/src/uts/common/sys/attr.h
index 34e802eed1..9f58bed52a 100644
--- a/usr/src/uts/common/sys/attr.h
+++ b/usr/src/uts/common/sys/attr.h
@@ -131,6 +131,7 @@ typedef struct {
#define XATTR_FIDSZ (sizeof (xattr_fid_t) - sizeof (uint16_t))
int xattr_dir_vget(vfs_t *, vnode_t **, fid_t *);
+int xattr_sysattr_casechk(char *name);
#endif
int attr_count(void);
diff --git a/usr/src/uts/common/sys/gfs.h b/usr/src/uts/common/sys/gfs.h
index b53031086b..2c0e0a2e6c 100644
--- a/usr/src/uts/common/sys/gfs.h
+++ b/usr/src/uts/common/sys/gfs.h
@@ -34,6 +34,7 @@
#include <sys/vfs_opreg.h>
#include <sys/mutex.h>
#include <sys/dirent.h>
+#include <sys/extdirent.h>
#include <sys/uio.h>
#include <sys/list.h>
#include <sys/pathname.h>
@@ -74,8 +75,8 @@ typedef struct gfs_file {
ino64_t gfs_ino; /* inode for this vnode */
} gfs_file_t;
-typedef int (*gfs_readdir_cb)(vnode_t *, struct dirent64 *, int *, offset_t *,
- offset_t *, void *);
+typedef int (*gfs_readdir_cb)(vnode_t *, void *, int *, offset_t *,
+ offset_t *, void *, int);
typedef int (*gfs_lookup_cb)(vnode_t *, const char *, vnode_t **, ino64_t *,
cred_t *);
typedef ino64_t (*gfs_inode_cb)(vnode_t *, int);
@@ -106,7 +107,7 @@ extern void *gfs_dir_inactive(vnode_t *);
extern int gfs_dir_lookup(vnode_t *, const char *, vnode_t **, cred_t *);
extern int gfs_dir_readdir(vnode_t *, uio_t *, int *, void *, cred_t *,
- caller_context_t *);
+ caller_context_t *, int flags);
#define gfs_dir_lock(gd) mutex_enter(&(gd)->gfsd_lock)
#define gfs_dir_unlock(gd) mutex_exit(&(gd)->gfsd_lock)
@@ -122,22 +123,25 @@ extern int gfs_dir_readdir(vnode_t *, uio_t *, int *, void *, cred_t *,
(((gfs_file_t *)(vp)->v_data)->gfs_ino = (ino))
typedef struct gfs_readdir_state {
- struct dirent64 *grd_dirent; /* directory entry buffer */
+ void *grd_dirent; /* directory entry buffer */
size_t grd_namlen; /* max file name length */
size_t grd_ureclen; /* exported record size */
ssize_t grd_oresid; /* original uio_resid */
ino64_t grd_parent; /* inode of parent */
ino64_t grd_self; /* inode of self */
+ int grd_flags; /* flags from VOP_READDIR */
} gfs_readdir_state_t;
extern int gfs_readdir_init(gfs_readdir_state_t *, int, int, uio_t *, ino64_t,
- ino64_t);
+ ino64_t, int);
extern int gfs_readdir_emit(gfs_readdir_state_t *, uio_t *, offset_t, ino64_t,
- const char *);
+ const char *, int);
extern int gfs_readdir_emitn(gfs_readdir_state_t *, uio_t *, offset_t, ino64_t,
unsigned long);
extern int gfs_readdir_pred(gfs_readdir_state_t *, uio_t *, offset_t *);
extern int gfs_readdir_fini(gfs_readdir_state_t *, int, int *, int);
+extern int gfs_get_parent_ino(vnode_t *, cred_t *, caller_context_t *,
+ ino64_t *, ino64_t *);
/*
* Objects with real extended attributes will get their . and ..