diff options
author | ck153898 <none@none> | 2007-12-10 12:25:48 -0800 |
---|---|---|
committer | ck153898 <none@none> | 2007-12-10 12:25:48 -0800 |
commit | b38f097029665f4ece801ca129913d36f757b49c (patch) | |
tree | 5ed7f4d7fb0fdae99be722118762b9249191a3d4 /usr/src/uts | |
parent | 423908e1eda59d79f1f867966cafecd54cfaa635 (diff) | |
download | illumos-gate-b38f097029665f4ece801ca129913d36f757b49c.tar.gz |
6627223 gfs needs to support extended dirent flags
Diffstat (limited to 'usr/src/uts')
-rw-r--r-- | usr/src/uts/common/fs/ctfs/ctfs_all.c | 17 | ||||
-rw-r--r-- | usr/src/uts/common/fs/ctfs/ctfs_tdir.c | 17 | ||||
-rw-r--r-- | usr/src/uts/common/fs/gfs.c | 136 | ||||
-rw-r--r-- | usr/src/uts/common/fs/objfs/objfs_root.c | 19 | ||||
-rw-r--r-- | usr/src/uts/common/fs/proc/prvnops.c | 31 | ||||
-rw-r--r-- | usr/src/uts/common/fs/xattr.c | 96 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/dmu_objset.c | 4 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/sys/dmu.h | 2 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/zfs_ctldir.c | 32 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/zfs_ioctl.c | 2 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/zfs_vnops.c | 17 | ||||
-rw-r--r-- | usr/src/uts/common/sys/attr.h | 1 | ||||
-rw-r--r-- | usr/src/uts/common/sys/gfs.h | 16 |
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 .. |