summaryrefslogtreecommitdiffstats
path: root/sys/fs/tmpfs/tmpfs_vnops.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/fs/tmpfs/tmpfs_vnops.c')
-rw-r--r--sys/fs/tmpfs/tmpfs_vnops.c43
1 files changed, 41 insertions, 2 deletions
diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c
index 88e0939..295d2ca 100644
--- a/sys/fs/tmpfs/tmpfs_vnops.c
+++ b/sys/fs/tmpfs/tmpfs_vnops.c
@@ -109,14 +109,19 @@ tmpfs_lookup(struct vop_cachedlookup_args *v)
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)
@@ -834,6 +839,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
@@ -904,6 +911,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. */
@@ -1099,6 +1108,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);
}
@@ -1223,6 +1236,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);
/* No vnode should be allocated for this entry from this point */
TMPFS_NODE_LOCK(node);
@@ -1541,6 +1556,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");
+ }
+}
+
/* --------------------------------------------------------------------- */
/*
@@ -1573,6 +1611,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,
};
OpenPOWER on IntegriCloud