Date: Thu, 13 Nov 2003 12:11:27 -0800 (PST) From: Chris Vance <cvance@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 42266 for review Message-ID: <200311132011.hADKBRaw046531@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=42266 Change 42266 by cvance@cvance_osx_laptop on 2003/11/13 12:10:46 With this submission, HFS supports basic extattr use. Only the autostart mechanism is supported, along with get & set operations. - Added shutdown routines - Added ENOATTR error code - Added support for the hfs_sextattr_set operation - Removed extaneous debugging Affected files ... .. //depot/projects/trustedbsd/sedarwin/apsl/xnu/bsd/hfs/hfs_extattr.c#4 edit .. //depot/projects/trustedbsd/sedarwin/apsl/xnu/bsd/hfs/hfs_vfsops.c#4 edit .. //depot/projects/trustedbsd/sedarwin/apsl/xnu/bsd/sys/errno.h#2 edit Differences ... ==== //depot/projects/trustedbsd/sedarwin/apsl/xnu/bsd/hfs/hfs_extattr.c#4 (text+ko) ==== @@ -59,6 +59,12 @@ #ifdef HFS_EXTATTR +/* XXX/TBD: This should be available via a sysctl */ +static hfs_extattr_sync = 0; + +static int hfs_extattr_disable(struct hfsmount *hfsmp, int attrnamespace, + const char *attrname, struct proc *p); + /* * Lock functions copied/ported From FreeBSD 5.1, including comments... * @@ -154,7 +160,7 @@ panic("hfs_extattr_uepm_destroy: not initialized"); if ((uepm->uepm_flags & HFS_EXTATTR_UEPM_STARTED)) - panic("Hfs_extattr_uepm_destroy: called while still started"); + panic("hfs_extattr_uepm_destroy: called while still started"); simple_lock(&mountlist_slock); uepm->uepm_flags &= ~HFS_EXTATTR_UEPM_INITIALIZED; @@ -211,7 +217,6 @@ struct vnode *target_vp; int error; - printf("hfs_extattr_lookup: called with dirname=%s\n", dirname); bzero(&cnp, sizeof(cnp)); cnp.cn_nameiop = LOOKUP; cnp.cn_flags = ISLASTCN; @@ -229,7 +234,6 @@ VOP_UNLOCK(start_dvp, 0, p); } _FREE_ZONE(cnp.cn_pnbuf, cnp.cn_pnlen, M_NAMEI); - printf("hfs_extattr_lookup: copystr failed\n"); return (error); } cnp.cn_namelen--; /* trim nul termination */ @@ -255,7 +259,6 @@ if (lockparent == UE_GETDIR_LOCKPARENT) panic("hfs_extattr_lookup: lockparent but PDIRUNLOCK"); */ - printf("hfs_extattr_lookup: hfs_lookup failed with error %d\n", error); return (error); } /* @@ -272,7 +275,6 @@ panic("hfs_extattr_lookup: lockparent but PDIRUNLOCK"); */ - printf("hfs_extattr_lookup: success, vp=%x\n", vp); *vp = target_vp; return (0); } @@ -337,20 +339,16 @@ goto unlock_free_exit; if (auio.uio_resid != 0) { - printf("hfs_extattr_enable: malformed attribute header\n"); error = EINVAL; goto unlock_free_exit; } if (attribute->uele_fileheader.uef_magic != HFS_EXTATTR_MAGIC) { - printf("hfs_extattr_enable: invalid attribute header magic\n"); error = EINVAL; goto unlock_free_exit; } if (attribute->uele_fileheader.uef_version != HFS_EXTATTR_VERSION) { - printf("hfs_extattr_enable: incorrect attribute header " - "version\n"); error = EINVAL; goto unlock_free_exit; } @@ -392,8 +390,6 @@ error = VOP_OPEN(vp, FREAD|FWRITE, p->p_ucred, p); if (error) { ubc_rele(vp); - printf("hfs_extattr_enable_with_open.VOP_OPEN(): failed " - "with %d\n", error); VOP_UNLOCK(vp, 0, p); return (error); } @@ -408,6 +404,8 @@ error = hfs_extattr_enable(hfsmp, attrnamespace, attrname, vp, p); if (error != 0) vn_close(vp, FREAD|FWRITE, p->p_ucred, p); + + return (error); } @@ -462,8 +460,6 @@ aiov.iov_len = DIRBLKSIZ; error = hfs_readdir(&vargs); if (error) { - printf("hfs_extattr_iterate_directory: hfs_readdir " - "%d\n", error); return (error); } @@ -490,11 +486,7 @@ error = hfs_extattr_enable_with_open(hfsmp, attr_vp, attrnamespace, dp->d_name, p); vrele(attr_vp); - if (error) { - printf("hfs_extattr_iterate_directory: " - "enable %s %d\n", dp->d_name, - error); - } else { + if (!error) { printf("HFS autostarted EA %s\n", dp->d_name); } @@ -518,7 +510,6 @@ hfs_extattr_autostart(struct mount *mp, struct proc *p) { - printf("hfs_extattr_autostart called\n"); struct vnode *rvp, *attr_dvp, *attr_system_dvp, *attr_user_dvp; int error; @@ -528,8 +519,6 @@ */ error = VFS_ROOT(mp, &rvp); if (error) { - printf("hfs_extattr_autostart.VFS_ROOT() returned %d\n", - error); return (error); } @@ -556,8 +545,6 @@ error = hfs_extattr_start(mp, p); if (error) { - printf("hfs_extattr_autostart: hfs_extattr_start failed (%d)\n", - error); goto return_vput_attr_dvp; } @@ -573,9 +560,6 @@ if (!error) { error = hfs_extattr_iterate_directory(VFSTOHFS(mp), attr_system_dvp, EXTATTR_NAMESPACE_SYSTEM, p); - if (error) - printf("hfs_extattr_iterate_directory returned %d\n", - error); vput(attr_system_dvp); } @@ -584,9 +568,6 @@ if (!error) { error = hfs_extattr_iterate_directory(VFSTOHFS(mp), attr_user_dvp, EXTATTR_NAMESPACE_USER, p); - if (error) - printf("hfs_extattr_iterate_directory returned %d\n", - error); vput(attr_user_dvp); } @@ -606,8 +587,32 @@ hfs_extattr_stop(struct mount *mp, struct proc *p) { - printf("hfs_extattr_stop called\n"); - return (0); + struct hfs_extattr_list_entry *uele; + struct hfsmount *hfsmp = VFSTOHFS(mp); + int error = 0; + + hfs_extattr_uepm_lock(hfsmp, p); + + if (!(hfsmp->hfs_extattr.uepm_flags & HFS_EXTATTR_UEPM_STARTED)) { + error = EOPNOTSUPP; + goto unlock; + } + + while (LIST_FIRST(&hfsmp->hfs_extattr.uepm_list) != NULL) { + uele = LIST_FIRST(&hfsmp->hfs_extattr.uepm_list); + hfs_extattr_disable(hfsmp, uele->uele_attrnamespace, + uele->uele_attrname, p); + } + + hfsmp->hfs_extattr.uepm_flags &= ~HFS_EXTATTR_UEPM_STARTED; + + crfree(hfsmp->hfs_extattr.uepm_ucred); + hfsmp->hfs_extattr.uepm_ucred = NULL; + +unlock: + hfs_extattr_uepm_unlock(hfsmp, p); + + return (error); } /* @@ -619,7 +624,149 @@ struct uio *uio, size_t *size, struct ucred *cred, struct proc *p) { - return (ENOTSUP); + struct hfs_extattr_list_entry *attribute; + struct hfs_extattr_header ueh; + struct iovec local_aiov; + struct uio local_aio; + struct mount *mp = vp->v_mount; + struct hfsmount *hfsmp = VFSTOHFS(mp); + struct cnode *cp = VTOC(vp); + off_t base_offset; + size_t len, old_len; + int error = 0; + + if (!(hfsmp->hfs_extattr.uepm_flags & HFS_EXTATTR_UEPM_STARTED)) + return (EOPNOTSUPP); + + if (strlen(name) == 0) + return (EINVAL); + +/* + * XXX/TBD: + */ +/* + error = extattr_check_cred(vp, attrnamespace, cred, p, IREAD); + if (error) + return (error); +*/ + + attribute = hfs_extattr_find_attr(hfsmp, attrnamespace, name); + if (!attribute) + return (ENOATTR); + + /* + * Allow only offsets of zero to encourage the read/replace + * extended attribute semantic. Otherwise we can't guarantee + * atomicity, as we don't provide locks for extended attributes. + */ + if (uio != NULL && uio->uio_offset != 0) + return (ENXIO); + + /* + * Find base offset of header in file based on file header size, and + * data header size + maximum data size, indexed by inode number. + */ + base_offset = sizeof(struct hfs_extattr_fileheader) + + cp->c_fileid * (sizeof(struct hfs_extattr_header) + + attribute->uele_fileheader.uef_size); + + /* + * Read in the data header to see if the data is defined, and if so + * how much. + */ + bzero(&ueh, sizeof(struct hfs_extattr_header)); + local_aiov.iov_base = (caddr_t) &ueh; + local_aiov.iov_len = sizeof(struct hfs_extattr_header); + local_aio.uio_iov = &local_aiov; + local_aio.uio_iovcnt = 1; + local_aio.uio_rw = UIO_READ; + local_aio.uio_segflg = UIO_SYSSPACE; + local_aio.uio_procp = p; + local_aio.uio_offset = base_offset; + local_aio.uio_resid = sizeof(struct hfs_extattr_header); + + /* + * Acquire locks. + */ + VOP_LEASE(attribute->uele_backing_vnode, p, cred, LEASE_READ); + /* + * Don't need to get a lock on the backing file if the getattr is + * being applied to the backing file, as the lock is already held. + */ + if (attribute->uele_backing_vnode != vp) + vn_lock(attribute->uele_backing_vnode, LK_SHARED | + LK_RETRY, p); + + error = VOP_READ(attribute->uele_backing_vnode, &local_aio, + IO_NODELOCKED, hfsmp->hfs_extattr.uepm_ucred); + if (error) + goto vopunlock_exit; + + /* Defined? */ + if ((ueh.ueh_flags & HFS_EXTATTR_ATTR_FLAG_INUSE) == 0) { + error = ENOATTR; + goto vopunlock_exit; + } + +#ifdef HFS_GENERATIONS + /* XXX/TBD: is there something similiar in hfs? */ + + /* Valid for the current inode generation? */ + if (ueh.ueh_i_gen != ip->i_gen) { + /* + * The inode itself has a different generation number + * than the attribute data. For now, the best solution + * is to coerce this to undefined, and let it get cleaned + * up by the next write or extattrctl clean. + */ + printf("hfs_extattr_get (%s): inode number inconsistency (%d, %jd)\n", + mp->mnt_stat.f_mntonname, ueh.ueh_i_gen, (intmax_t)ip->i_gen); + error = ENOATTR; + goto vopunlock_exit; + } +#endif + + /* Local size consistency check. */ + if (ueh.ueh_len > attribute->uele_fileheader.uef_size) { + error = ENXIO; + goto vopunlock_exit; + } + + /* Return full data size if caller requested it. */ + if (size != NULL) + *size = ueh.ueh_len; + + /* Return data if the caller requested it. */ + if (uio != NULL) { + /* Allow for offset into the attribute data. */ + uio->uio_offset = base_offset + sizeof(struct + hfs_extattr_header); + + /* + * Figure out maximum to transfer -- use buffer size and + * local data limit. + */ + len = MIN(uio->uio_resid, ueh.ueh_len); + old_len = uio->uio_resid; + uio->uio_resid = len; + + error = VOP_READ(attribute->uele_backing_vnode, uio, + IO_NODELOCKED, hfsmp->hfs_extattr.uepm_ucred); + if (error) + goto vopunlock_exit; + + uio->uio_resid = old_len - (len - uio->uio_resid); + } + +vopunlock_exit: + + if (uio != NULL) + uio->uio_offset = 0; + + if (attribute->uele_backing_vnode != vp) + VOP_UNLOCK(attribute->uele_backing_vnode, 0, p); + + return (error); } /* @@ -630,8 +777,119 @@ hfs_extattr_set(struct vnode *vp, int attrnamespace, const char *name, struct uio *uio, struct ucred *cred, struct proc *p) { + struct hfs_extattr_list_entry *attribute; + struct hfs_extattr_header ueh; + struct iovec local_aiov; + struct uio local_aio; + struct mount *mp = vp->v_mount; + struct hfsmount *hfsmp = VFSTOHFS(mp); + struct cnode *cp = VTOC(vp); + off_t base_offset; + int error = 0, ioflag; + + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + if (!(hfsmp->hfs_extattr.uepm_flags & HFS_EXTATTR_UEPM_STARTED)) + return (EOPNOTSUPP); + if (!hfs_extattr_valid_attrname(attrnamespace, name)) + return (EINVAL); + +/* + * XXX/TBD: + */ +/* + error = extattr_check_cred(vp, attrnamespace, cred, td, IWRITE); + if (error) + return (error); +*/ + attribute = hfs_extattr_find_attr(hfsmp, attrnamespace, name); - return (ENOTSUP); + if (!attribute) { + return (ENOATTR); + } + + /* + * Early rejection of invalid offsets/length. + * Reject: any offset but 0 (replace) + * Any size greater than attribute size limit + */ + if (uio->uio_offset != 0 || + uio->uio_resid > attribute->uele_fileheader.uef_size) { + return (ENXIO); + } + + /* + * Find base offset of header in file based on file header size, and + * data header size + maximum data size, indexed by inode number. + */ + base_offset = sizeof(struct hfs_extattr_fileheader) + + cp->c_fileid * (sizeof(struct hfs_extattr_header) + + attribute->uele_fileheader.uef_size); + + /* + * Write out a data header for the data. + */ + ueh.ueh_len = uio->uio_resid; + ueh.ueh_flags = HFS_EXTATTR_ATTR_FLAG_INUSE; +#ifdef HFS_GENERATIONS + /* XXX/TBD: is there something similiar in hfs? */ + ueh.ueh_i_gen = ip->i_gen; +#endif + local_aiov.iov_base = (caddr_t) &ueh; + local_aiov.iov_len = sizeof(struct hfs_extattr_header); + local_aio.uio_iov = &local_aiov; + local_aio.uio_iovcnt = 1; + local_aio.uio_rw = UIO_WRITE; + local_aio.uio_segflg = UIO_SYSSPACE; + local_aio.uio_procp = p; + local_aio.uio_offset = base_offset; + local_aio.uio_resid = sizeof(struct hfs_extattr_header); + + /* + * Acquire locks. + */ + VOP_LEASE(attribute->uele_backing_vnode, p, cred, LEASE_WRITE); + + /* + * Don't need to get a lock on the backing file if the setattr is + * being applied to the backing file, as the lock is already held. + */ + if (attribute->uele_backing_vnode != vp) + vn_lock(attribute->uele_backing_vnode, + LK_EXCLUSIVE | LK_RETRY, p); + + ioflag = IO_NODELOCKED; + if (hfs_extattr_sync) + ioflag |= IO_SYNC; + error = VOP_WRITE(attribute->uele_backing_vnode, &local_aio, ioflag, + hfsmp->hfs_extattr.uepm_ucred); + if (error) { + goto vopunlock_exit; + } + + if (local_aio.uio_resid != 0) { + error = ENXIO; + goto vopunlock_exit; + } + + /* + * Write out user data. + */ + uio->uio_offset = base_offset + sizeof(struct hfs_extattr_header); + + ioflag = IO_NODELOCKED; + if (hfs_extattr_sync) + ioflag |= IO_SYNC; + error = VOP_WRITE(attribute->uele_backing_vnode, uio, ioflag, + hfsmp->hfs_extattr.uepm_ucred); + +vopunlock_exit: + uio->uio_offset = 0; + + if (attribute->uele_backing_vnode != vp) + VOP_UNLOCK(attribute->uele_backing_vnode, 0, p); + + return (error); } /* @@ -667,7 +925,6 @@ struct hfsmount *hfsmp = VTOHFS(ap->a_vp); int error; - printf("hfs_getextattr called\n"); hfs_extattr_uepm_lock(hfsmp, ap->a_p); @@ -700,7 +957,6 @@ int error; - printf("hfs_setextattr called\n"); hfs_extattr_uepm_lock(hfsmp, ap->a_p); /* @@ -749,5 +1005,38 @@ return (error); } +/* + * Disable extended attribute support on an FS. + */ +static int +hfs_extattr_disable(struct hfsmount *hfsmp, int attrnamespace, + const char *attrname, struct proc *p) +{ + struct hfs_extattr_list_entry *uele; + int error = 0; + + if (!hfs_extattr_valid_attrname(attrnamespace, attrname)) { + return (EINVAL); + } + + uele = hfs_extattr_find_attr(hfsmp, attrnamespace, attrname); + if (!uele) { + return (ENOATTR); + } + + LIST_REMOVE(uele, uele_entries); + + vn_lock(uele->uele_backing_vnode, LK_SHARED | LK_RETRY, p); +/* XXX/TBD */ +/* ASSERT_VOP_LOCKED(uele->uele_backing_vnode, "hfs_extattr_disable"); */ + uele->uele_backing_vnode->v_flag &= ~VSYSTEM; + VOP_UNLOCK(uele->uele_backing_vnode, 0, p); + error = vn_close(uele->uele_backing_vnode, FREAD|FWRITE, + p->p_ucred, p); + + FREE(uele, M_EXTATTR); + + return (error); +} #endif /* !HFS_EXTATTR */ ==== //depot/projects/trustedbsd/sedarwin/apsl/xnu/bsd/hfs/hfs_vfsops.c#4 (text+ko) ==== @@ -1225,11 +1225,11 @@ force = 1; } -#ifdef UFS_EXTATTR - if ((error = hfs_extattr_stop(mp, p))) { - if (error != ENOTSUP) +#ifdef HFS_EXTATTR + if ((retval = hfs_extattr_stop(mp, p))) { + if (retval != ENOTSUP) printf("hfs_unmount: hfs_extattr_stop returned %d\n", - error); + retval); } else { hfs_extattr_uepm_destroy(&hfsmp->hfs_extattr, p); } ==== //depot/projects/trustedbsd/sedarwin/apsl/xnu/bsd/sys/errno.h#2 (text+ko) ==== @@ -205,7 +205,8 @@ #define EBADMACHO 88 /* Malformed Macho file */ #define ECANCELED 89 /* Operation canceled */ -#define ELAST 89 /* Must be equal largest errno */ +#define ENOATTR 90 /* Attribute not found */ +#define ELAST 90 /* Must be equal largest errno */ #endif /* _POSIX_SOURCE */ #ifdef KERNEL
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200311132011.hADKBRaw046531>