Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 21 Sep 2010 07:01:00 +0000 (UTC)
From:      Ed Schouten <ed@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r212953 - stable/8/sys/fs/tmpfs
Message-ID:  <201009210701.o8L710Fg082611@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ed
Date: Tue Sep 21 07:01:00 2010
New Revision: 212953
URL: http://svn.freebsd.org/changeset/base/212953

Log:
  MFC r211598:
  
    Add support for whiteouts on tmpfs.
  
    Right now unionfs only allows filesystems to be mounted on top of
    another if it supports whiteouts. Even though I have sent a patch to
    daichi@ to let unionfs work without it, we'd better also add support for
    whiteouts to tmpfs.
  
    This patch implements .vop_whiteout and makes necessary changes to
    lookup() and readdir() to take them into account. We must also make sure
    that when adding or removing a file, we honour the componentname's
    DOWHITEOUT and ISWHITEOUT, to prevent duplicate filenames.

Modified:
  stable/8/sys/fs/tmpfs/tmpfs.h
  stable/8/sys/fs/tmpfs/tmpfs_subr.c
  stable/8/sys/fs/tmpfs/tmpfs_vnops.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/xen/xenpci/   (props changed)

Modified: stable/8/sys/fs/tmpfs/tmpfs.h
==============================================================================
--- stable/8/sys/fs/tmpfs/tmpfs.h	Tue Sep 21 06:47:04 2010	(r212952)
+++ stable/8/sys/fs/tmpfs/tmpfs.h	Tue Sep 21 07:01:00 2010	(r212953)
@@ -72,7 +72,8 @@ struct tmpfs_dirent {
 	* td_namelen field must always be used when accessing its value. */
 	char *				td_name;
 
-	/* Pointer to the node this entry refers to. */
+	/* Pointer to the node this entry refers to.  In case this field
+	 * is NULL, the node is a whiteout. */
 	struct tmpfs_node *		td_node;
 };
 
@@ -414,6 +415,8 @@ int	tmpfs_dir_getdotdent(struct tmpfs_no
 int	tmpfs_dir_getdotdotdent(struct tmpfs_node *, struct uio *);
 struct tmpfs_dirent *	tmpfs_dir_lookupbycookie(struct tmpfs_node *, off_t);
 int	tmpfs_dir_getdents(struct tmpfs_node *, struct uio *, off_t *);
+int	tmpfs_dir_whiteout_add(struct vnode *, struct componentname *);
+void	tmpfs_dir_whiteout_remove(struct vnode *, struct componentname *);
 int	tmpfs_reg_resize(struct vnode *, off_t);
 int	tmpfs_chflags(struct vnode *, int, struct ucred *, struct thread *);
 int	tmpfs_chmod(struct vnode *, mode_t, struct ucred *, struct thread *);

Modified: stable/8/sys/fs/tmpfs/tmpfs_subr.c
==============================================================================
--- stable/8/sys/fs/tmpfs/tmpfs_subr.c	Tue Sep 21 06:47:04 2010	(r212952)
+++ stable/8/sys/fs/tmpfs/tmpfs_subr.c	Tue Sep 21 07:01:00 2010	(r212953)
@@ -258,7 +258,8 @@ tmpfs_alloc_dirent(struct tmpfs_mount *t
 	memcpy(nde->td_name, name, len);
 
 	nde->td_node = node;
-	node->tn_links++;
+	if (node != NULL)
+		node->tn_links++;
 
 	*de = nde;
 
@@ -284,9 +285,10 @@ tmpfs_free_dirent(struct tmpfs_mount *tm
 		struct tmpfs_node *node;
 
 		node = de->td_node;
-
-		MPASS(node->tn_links > 0);
-		node->tn_links--;
+		if (node != NULL) {
+			MPASS(node->tn_links > 0);
+			node->tn_links--;
+		}
 	}
 
 	free(de->td_name, M_TMPFSNAME);
@@ -506,6 +508,8 @@ tmpfs_alloc_file(struct vnode *dvp, stru
 	/* Now that all required items are allocated, we can proceed to
 	 * insert the new node into the directory, an operation that
 	 * cannot fail. */
+	if (cnp->cn_flags & ISWHITEOUT)
+		tmpfs_dir_whiteout_remove(dvp, cnp);
 	tmpfs_dir_attach(dvp, de);
 
 out:
@@ -745,39 +749,44 @@ tmpfs_dir_getdents(struct tmpfs_node *no
 
 		/* Create a dirent structure representing the current
 		 * tmpfs_node and fill it. */
-		d.d_fileno = de->td_node->tn_id;
-		switch (de->td_node->tn_type) {
-		case VBLK:
-			d.d_type = DT_BLK;
-			break;
-
-		case VCHR:
-			d.d_type = DT_CHR;
-			break;
-
-		case VDIR:
-			d.d_type = DT_DIR;
-			break;
-
-		case VFIFO:
-			d.d_type = DT_FIFO;
-			break;
-
-		case VLNK:
-			d.d_type = DT_LNK;
-			break;
-
-		case VREG:
-			d.d_type = DT_REG;
-			break;
-
-		case VSOCK:
-			d.d_type = DT_SOCK;
-			break;
-
-		default:
-			panic("tmpfs_dir_getdents: type %p %d",
-			    de->td_node, (int)de->td_node->tn_type);
+		if (de->td_node == NULL) {
+			d.d_fileno = 1;
+			d.d_type = DT_WHT;
+		} else {
+			d.d_fileno = de->td_node->tn_id;
+			switch (de->td_node->tn_type) {
+			case VBLK:
+				d.d_type = DT_BLK;
+				break;
+
+			case VCHR:
+				d.d_type = DT_CHR;
+				break;
+
+			case VDIR:
+				d.d_type = DT_DIR;
+				break;
+
+			case VFIFO:
+				d.d_type = DT_FIFO;
+				break;
+
+			case VLNK:
+				d.d_type = DT_LNK;
+				break;
+
+			case VREG:
+				d.d_type = DT_REG;
+				break;
+
+			case VSOCK:
+				d.d_type = DT_SOCK;
+				break;
+
+			default:
+				panic("tmpfs_dir_getdents: type %p %d",
+				    de->td_node, (int)de->td_node->tn_type);
+			}
 		}
 		d.d_namlen = de->td_namelen;
 		MPASS(de->td_namelen < sizeof(d.d_name));
@@ -814,6 +823,31 @@ tmpfs_dir_getdents(struct tmpfs_node *no
 	return error;
 }
 
+int
+tmpfs_dir_whiteout_add(struct vnode *dvp, struct componentname *cnp)
+{
+	struct tmpfs_dirent *de;
+	int error;
+
+	error = tmpfs_alloc_dirent(VFS_TO_TMPFS(dvp->v_mount), NULL,
+	    cnp->cn_nameptr, cnp->cn_namelen, &de);
+	if (error != 0)
+		return (error);
+	tmpfs_dir_attach(dvp, de);
+	return (0);
+}
+
+void
+tmpfs_dir_whiteout_remove(struct vnode *dvp, struct componentname *cnp)
+{
+	struct tmpfs_dirent *de;
+
+	de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(dvp), NULL, cnp);
+	MPASS(de != NULL && de->td_node == NULL);
+	tmpfs_dir_detach(dvp, de);
+	tmpfs_free_dirent(VFS_TO_TMPFS(dvp->v_mount), de, TRUE);
+}
+
 /* --------------------------------------------------------------------- */
 
 /*

Modified: stable/8/sys/fs/tmpfs/tmpfs_vnops.c
==============================================================================
--- stable/8/sys/fs/tmpfs/tmpfs_vnops.c	Tue Sep 21 06:47:04 2010	(r212952)
+++ stable/8/sys/fs/tmpfs/tmpfs_vnops.c	Tue Sep 21 07:01:00 2010	(r212953)
@@ -103,14 +103,19 @@ tmpfs_lookup(struct vop_cachedlookup_arg
 		error = 0;
 	} else {
 		de = tmpfs_dir_lookup(dnode, NULL, cnp);
-		if (de == NULL) {
+		if (de != NULL && de->td_node == NULL)
+			cnp->cn_flags |= ISWHITEOUT;
+		if (de == NULL || de->td_node == NULL) {
 			/* The entry was not found in the directory.
 			 * This is OK if we are creating or renaming an
 			 * entry and are working on the last component of
 			 * the path name. */
 			if ((cnp->cn_flags & ISLASTCN) &&
 			    (cnp->cn_nameiop == CREATE || \
-			    cnp->cn_nameiop == RENAME)) {
+			    cnp->cn_nameiop == RENAME ||
+			    (cnp->cn_nameiop == DELETE &&
+			    cnp->cn_flags & DOWHITEOUT &&
+			    cnp->cn_flags & ISWHITEOUT))) {
 				error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred,
 				    cnp->cn_thread);
 				if (error != 0)
@@ -757,6 +762,8 @@ tmpfs_remove(struct vop_remove_args *v)
 	/* Remove the entry from the directory; as it is a file, we do not
 	 * have to change the number of hard links of the directory. */
 	tmpfs_dir_detach(dvp, de);
+	if (v->a_cnp->cn_flags & DOWHITEOUT)
+		tmpfs_dir_whiteout_add(dvp, v->a_cnp);
 
 	/* Free the directory entry we just deleted.  Note that the node
 	 * referred by it will not be removed until the vnode is really
@@ -827,6 +834,8 @@ tmpfs_link(struct vop_link_args *v)
 		goto out;
 
 	/* Insert the new directory entry into the appropriate directory. */
+	if (cnp->cn_flags & ISWHITEOUT)
+		tmpfs_dir_whiteout_remove(dvp, cnp);
 	tmpfs_dir_attach(dvp, de);
 
 	/* vp link count has changed, so update node times. */
@@ -982,6 +991,10 @@ tmpfs_rename(struct vop_rename_args *v)
 		/* Do the move: just remove the entry from the source directory
 		 * and insert it into the target one. */
 		tmpfs_dir_detach(fdvp, de);
+		if (fcnp->cn_flags & DOWHITEOUT)
+			tmpfs_dir_whiteout_add(fdvp, fcnp);
+		if (tcnp->cn_flags & ISWHITEOUT)
+			tmpfs_dir_whiteout_remove(tdvp, tcnp);
 		tmpfs_dir_attach(tdvp, de);
 	}
 
@@ -1105,6 +1118,8 @@ tmpfs_rmdir(struct vop_rmdir_args *v)
 
 	/* Detach the directory entry from the directory (dnode). */
 	tmpfs_dir_detach(dvp, de);
+	if (v->a_cnp->cn_flags & DOWHITEOUT)
+		tmpfs_dir_whiteout_add(dvp, v->a_cnp);
 
 	node->tn_links--;
 	node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \
@@ -1405,6 +1420,29 @@ tmpfs_vptofh(struct vop_vptofh_args *ap)
 	return (0);
 }
 
+static int
+tmpfs_whiteout(struct vop_whiteout_args *ap)
+{
+	struct vnode *dvp = ap->a_dvp;
+	struct componentname *cnp = ap->a_cnp;
+	struct tmpfs_dirent *de;
+
+	switch (ap->a_flags) {
+	case LOOKUP:
+		return (0);
+	case CREATE:
+		de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(dvp), NULL, cnp);
+		if (de != NULL)
+			return (de->td_node == NULL ? 0 : EEXIST);
+		return (tmpfs_dir_whiteout_add(dvp, cnp));
+	case DELETE:
+		tmpfs_dir_whiteout_remove(dvp, cnp);
+		return (0);
+	default:
+		panic("tmpfs_whiteout: unknown op");
+	}
+}
+
 /* --------------------------------------------------------------------- */
 
 /*
@@ -1437,6 +1475,7 @@ struct vop_vector tmpfs_vnodeop_entries 
 	.vop_print =			tmpfs_print,
 	.vop_pathconf =			tmpfs_pathconf,
 	.vop_vptofh =			tmpfs_vptofh,
+	.vop_whiteout =			tmpfs_whiteout,
 	.vop_bmap =			VOP_EOPNOTSUPP,
 };
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201009210701.o8L710Fg082611>