svn commit: r212953 - stable/8/sys/fs/tmpfs
Ed Schouten
ed at FreeBSD.org
Tue Sep 21 07:01:01 UTC 2010
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,
};
More information about the svn-src-stable-8
mailing list