PERFORCE change 42266 for review

Chris Vance cvance at FreeBSD.org
Thu Nov 13 20:11:27 GMT 2003


http://perforce.freebsd.org/chv.cgi?CH=42266

Change 42266 by cvance at 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
To Unsubscribe: send mail to majordomo at trustedbsd.org
with "unsubscribe trustedbsd-cvs" in the body of the message



More information about the trustedbsd-cvs mailing list