Module Name: src
Committed By: rmind
Date: Sat Nov 23 16:35:32 UTC 2013
Modified Files:
src/sys/fs/tmpfs: tmpfs.h tmpfs_fifoops.c tmpfs_rename.c
tmpfs_specops.c tmpfs_subr.c tmpfs_vfsops.c tmpfs_vnops.c
Log Message:
- Simplify tmpfs_update(), eliminate tmpfs_note_t::tn_status and deferred
timestamp updates. Fix some incorrect updates and plug some missing ones.
Should fix PR/48385.
- tmpfs_rmdir: avoid O(n) scan when the directory is not empty and whiteout
entries were never added.
To generate a diff of this commit:
cvs rdiff -u -r1.47 -r1.48 src/sys/fs/tmpfs/tmpfs.h
cvs rdiff -u -r1.9 -r1.10 src/sys/fs/tmpfs/tmpfs_fifoops.c
cvs rdiff -u -r1.5 -r1.6 src/sys/fs/tmpfs/tmpfs_rename.c
cvs rdiff -u -r1.10 -r1.11 src/sys/fs/tmpfs/tmpfs_specops.c
cvs rdiff -u -r1.89 -r1.90 src/sys/fs/tmpfs/tmpfs_subr.c
cvs rdiff -u -r1.54 -r1.55 src/sys/fs/tmpfs/tmpfs_vfsops.c
cvs rdiff -u -r1.106 -r1.107 src/sys/fs/tmpfs/tmpfs_vnops.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/fs/tmpfs/tmpfs.h
diff -u src/sys/fs/tmpfs/tmpfs.h:1.47 src/sys/fs/tmpfs/tmpfs.h:1.48
--- src/sys/fs/tmpfs/tmpfs.h:1.47 Mon Nov 18 01:39:34 2013
+++ src/sys/fs/tmpfs/tmpfs.h Sat Nov 23 16:35:32 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: tmpfs.h,v 1.47 2013/11/18 01:39:34 rmind Exp $ */
+/* $NetBSD: tmpfs.h,v 1.48 2013/11/23 16:35:32 rmind Exp $ */
/*
* Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc.
@@ -101,9 +101,6 @@ typedef struct tmpfs_node {
ino_t tn_id;
uint32_t tn_gen;
- /* Inode status flags (for operations in delayed manner). */
- unsigned tn_status;
-
/* The inode size. */
off_t tn_size;
@@ -183,20 +180,18 @@ CTASSERT(TMPFS_MAXNAMLEN < UINT16_MAX);
/* Mark to indicate that the number is not set. */
#define TMPFS_DIRSEQ_NONE (1U << 31)
-/* Status flags. */
-#define TMPFS_NODE_ACCESSED 0x01
-#define TMPFS_NODE_MODIFIED 0x02
-#define TMPFS_NODE_CHANGED 0x04
-
-#define TMPFS_NODE_STATUSALL \
- (TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED | TMPFS_NODE_CHANGED)
+/* Flags: time update requests. */
+#define TMPFS_UPDATE_ATIME 0x01
+#define TMPFS_UPDATE_MTIME 0x02
+#define TMPFS_UPDATE_CTIME 0x04
/*
- * Bit indicating vnode reclamation.
+ * Bits indicating vnode reclamation and whiteout use for the directory.
* We abuse tmpfs_node_t::tn_gen for that.
*/
#define TMPFS_RECLAIMING_BIT (1U << 31)
-#define TMPFS_NODE_GEN_MASK (TMPFS_RECLAIMING_BIT - 1)
+#define TMPFS_WHITEOUT_BIT (1U << 30)
+#define TMPFS_NODE_GEN_MASK (TMPFS_WHITEOUT_BIT - 1)
#define TMPFS_NODE_RECLAIMING(node) \
(((node)->tn_gen & TMPFS_RECLAIMING_BIT) != 0)
@@ -249,7 +244,7 @@ int tmpfs_alloc_node(tmpfs_mount_t *, e
mode_t, char *, dev_t, tmpfs_node_t **);
void tmpfs_free_node(tmpfs_mount_t *, tmpfs_node_t *);
-int tmpfs_alloc_file(vnode_t *, vnode_t **, struct vattr *,
+int tmpfs_construct_node(vnode_t *, vnode_t **, struct vattr *,
struct componentname *, char *);
int tmpfs_vnode_get(struct mount *, tmpfs_node_t *, vnode_t **);
@@ -268,7 +263,6 @@ tmpfs_dirent_t *tmpfs_dir_lookupbyseq(tm
int tmpfs_dir_getdents(tmpfs_node_t *, struct uio *, off_t *);
int tmpfs_reg_resize(vnode_t *, off_t);
-int tmpfs_truncate(vnode_t *, off_t);
int tmpfs_chflags(vnode_t *, int, kauth_cred_t, lwp_t *);
int tmpfs_chmod(vnode_t *, mode_t, kauth_cred_t, lwp_t *);
@@ -277,8 +271,7 @@ int tmpfs_chsize(vnode_t *, u_quad_t, k
int tmpfs_chtimes(vnode_t *, const struct timespec *,
const struct timespec *, const struct timespec *, int,
kauth_cred_t, lwp_t *);
-void tmpfs_update(vnode_t *, const struct timespec *,
- const struct timespec *, const struct timespec *, int);
+void tmpfs_update(vnode_t *, unsigned);
/*
* Prototypes for tmpfs_mem.c.
Index: src/sys/fs/tmpfs/tmpfs_fifoops.c
diff -u src/sys/fs/tmpfs/tmpfs_fifoops.c:1.9 src/sys/fs/tmpfs/tmpfs_fifoops.c:1.10
--- src/sys/fs/tmpfs/tmpfs_fifoops.c:1.9 Tue May 24 20:17:49 2011
+++ src/sys/fs/tmpfs/tmpfs_fifoops.c Sat Nov 23 16:35:32 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: tmpfs_fifoops.c,v 1.9 2011/05/24 20:17:49 rmind Exp $ */
+/* $NetBSD: tmpfs_fifoops.c,v 1.10 2013/11/23 16:35:32 rmind Exp $ */
/*
* Copyright (c) 2005 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tmpfs_fifoops.c,v 1.9 2011/05/24 20:17:49 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tmpfs_fifoops.c,v 1.10 2013/11/23 16:35:32 rmind Exp $");
#include <sys/param.h>
#include <sys/vnode.h>
@@ -103,10 +103,8 @@ tmpfs_fifo_close(void *v)
struct vnode *a_vp;
int a_fflag;
kauth_cred_t a_cred;
- } */ *ap = v;
- vnode_t *vp = ap->a_vp;
+ } */ *ap __unused = v;
- tmpfs_update(vp, NULL, NULL, NULL, UPDATE_CLOSE);
return VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), v);
}
@@ -121,7 +119,7 @@ tmpfs_fifo_read(void *v)
} */ *ap = v;
vnode_t *vp = ap->a_vp;
- VP_TO_TMPFS_NODE(vp)->tn_status |= TMPFS_NODE_ACCESSED;
+ tmpfs_update(vp, TMPFS_UPDATE_ATIME);
return VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), v);
}
@@ -136,6 +134,6 @@ tmpfs_fifo_write(void *v)
} */ *ap = v;
vnode_t *vp = ap->a_vp;
- VP_TO_TMPFS_NODE(vp)->tn_status |= TMPFS_NODE_MODIFIED;
+ tmpfs_update(vp, TMPFS_UPDATE_MTIME);
return VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), v);
}
Index: src/sys/fs/tmpfs/tmpfs_rename.c
diff -u src/sys/fs/tmpfs/tmpfs_rename.c:1.5 src/sys/fs/tmpfs/tmpfs_rename.c:1.6
--- src/sys/fs/tmpfs/tmpfs_rename.c:1.5 Fri Nov 8 15:44:23 2013
+++ src/sys/fs/tmpfs/tmpfs_rename.c Sat Nov 23 16:35:32 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: tmpfs_rename.c,v 1.5 2013/11/08 15:44:23 rmind Exp $ */
+/* $NetBSD: tmpfs_rename.c,v 1.6 2013/11/23 16:35:32 rmind Exp $ */
/*-
* Copyright (c) 2012 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tmpfs_rename.c,v 1.5 2013/11/08 15:44:23 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tmpfs_rename.c,v 1.6 2013/11/23 16:35:32 rmind Exp $");
#include <sys/param.h>
#include <sys/errno.h>
@@ -266,6 +266,8 @@ tmpfs_gro_rename(struct mount *mp, kauth
struct vnode *tdvp, struct componentname *tcnp,
void *tde, struct vnode *tvp)
{
+ tmpfs_node_t *fdnode = VP_TO_TMPFS_DIR(fdvp);
+ tmpfs_node_t *tdnode = VP_TO_TMPFS_DIR(tdvp);
struct tmpfs_dirent **fdep = fde;
struct tmpfs_dirent **tdep = tde;
char *newname;
@@ -313,9 +315,6 @@ tmpfs_gro_rename(struct mount *mp, kauth
* source entry and reattach it to the target directory.
*/
if (fdvp != tdvp) {
- tmpfs_node_t *fdnode = VP_TO_TMPFS_DIR(fdvp);
- tmpfs_node_t *tdnode = VP_TO_TMPFS_DIR(tdvp);
-
tmpfs_dir_detach(fdnode, *fdep);
tmpfs_dir_attach(tdnode, *fdep, VP_TO_TMPFS_NODE(fvp));
} else if (tvp == NULL) {
@@ -334,7 +333,7 @@ tmpfs_gro_rename(struct mount *mp, kauth
* XXX What if the target is a directory with whiteout entries?
*/
if (tvp != NULL) {
- tmpfs_node_t *tdnode = VP_TO_TMPFS_DIR(tdvp);
+ tdnode = VP_TO_TMPFS_DIR(tdvp);
KASSERT((*tdep) != NULL);
KASSERT((*tdep)->td_node == VP_TO_TMPFS_NODE(tvp));
@@ -346,11 +345,6 @@ tmpfs_gro_rename(struct mount *mp, kauth
/*
* Decrement the extra link count for `.' so
* the vnode will be recycled when released.
- *
- * XXX Why not just release directory vnodes
- * when their link count is 1 instead of 0 in
- * tmpfs_inactive, since `.' is being treated
- * specially anyway?
*/
VP_TO_TMPFS_NODE(tvp)->tn_links--;
}
@@ -373,11 +367,16 @@ tmpfs_gro_rename(struct mount *mp, kauth
(*fdep)->td_namelen = (uint16_t)tcnp->cn_namelen;
(void)memcpy(newname, tcnp->cn_nameptr, tcnp->cn_namelen);
(*fdep)->td_name = newname;
-
- VP_TO_TMPFS_NODE(fvp)->tn_status |= TMPFS_NODE_CHANGED;
- VP_TO_TMPFS_NODE(tdvp)->tn_status |= TMPFS_NODE_MODIFIED;
}
+ /*
+ * Update the timestamps of both parent directories and
+ * the renamed file itself.
+ */
+ tmpfs_update(fdvp, TMPFS_UPDATE_MTIME | TMPFS_UPDATE_CTIME);
+ tmpfs_update(tdvp, TMPFS_UPDATE_MTIME | TMPFS_UPDATE_CTIME);
+ tmpfs_update(fvp, TMPFS_UPDATE_CTIME);
+
VN_KNOTE(fvp, NOTE_RENAME);
genfs_rename_cache_purge(fdvp, fvp, tdvp, tvp);
@@ -412,6 +411,7 @@ tmpfs_gro_remove(struct mount *mp, kauth
tmpfs_dir_detach(dnode, *dep);
tmpfs_free_dirent(VFS_TO_TMPFS(mp), *dep);
+ tmpfs_update(dvp, TMPFS_UPDATE_MTIME | TMPFS_UPDATE_CTIME);
return 0;
}
Index: src/sys/fs/tmpfs/tmpfs_specops.c
diff -u src/sys/fs/tmpfs/tmpfs_specops.c:1.10 src/sys/fs/tmpfs/tmpfs_specops.c:1.11
--- src/sys/fs/tmpfs/tmpfs_specops.c:1.10 Tue May 24 20:17:49 2011
+++ src/sys/fs/tmpfs/tmpfs_specops.c Sat Nov 23 16:35:32 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: tmpfs_specops.c,v 1.10 2011/05/24 20:17:49 rmind Exp $ */
+/* $NetBSD: tmpfs_specops.c,v 1.11 2013/11/23 16:35:32 rmind Exp $ */
/*
* Copyright (c) 2005 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tmpfs_specops.c,v 1.10 2011/05/24 20:17:49 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tmpfs_specops.c,v 1.11 2013/11/23 16:35:32 rmind Exp $");
#include <sys/param.h>
#include <sys/vnode.h>
@@ -106,10 +106,8 @@ tmpfs_spec_close(void *v)
struct vnode *a_vp;
int a_fflag;
kauth_cred_t a_cred;
- } */ *ap = v;
- vnode_t *vp = ap->a_vp;
+ } */ *ap __unused = v;
- tmpfs_update(vp, NULL, NULL, NULL, UPDATE_CLOSE);
return VOCALL(spec_vnodeop_p, VOFFSET(vop_close), v);
}
@@ -124,7 +122,7 @@ tmpfs_spec_read(void *v)
} */ *ap = v;
vnode_t *vp = ap->a_vp;
- VP_TO_TMPFS_NODE(vp)->tn_status |= TMPFS_NODE_ACCESSED;
+ tmpfs_update(vp, TMPFS_UPDATE_ATIME);
return VOCALL(spec_vnodeop_p, VOFFSET(vop_read), v);
}
@@ -139,6 +137,6 @@ tmpfs_spec_write(void *v)
} */ *ap = v;
vnode_t *vp = ap->a_vp;
- VP_TO_TMPFS_NODE(vp)->tn_status |= TMPFS_NODE_MODIFIED;
+ tmpfs_update(vp, TMPFS_UPDATE_MTIME);
return VOCALL(spec_vnodeop_p, VOFFSET(vop_write), v);
}
Index: src/sys/fs/tmpfs/tmpfs_subr.c
diff -u src/sys/fs/tmpfs/tmpfs_subr.c:1.89 src/sys/fs/tmpfs/tmpfs_subr.c:1.90
--- src/sys/fs/tmpfs/tmpfs_subr.c:1.89 Thu Nov 21 14:39:09 2013
+++ src/sys/fs/tmpfs/tmpfs_subr.c Sat Nov 23 16:35:32 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: tmpfs_subr.c,v 1.89 2013/11/21 14:39:09 rmind Exp $ */
+/* $NetBSD: tmpfs_subr.c,v 1.90 2013/11/23 16:35:32 rmind Exp $ */
/*
* Copyright (c) 2005-2013 The NetBSD Foundation, Inc.
@@ -59,7 +59,7 @@
* reference counting and link counting. That is, an inode can only be
* destroyed if its associated vnode is inactive. The destruction is
* done on vnode reclamation i.e. tmpfs_reclaim(). It should be noted
- * that tmpfs_node_t::tn_links being 0 is a destruction criterion.
+ * that tmpfs_node_t::tn_links being 0 is a destruction criterion.
*
* If an inode has references within the file system (tn_links > 0) and
* its inactive vnode gets reclaimed/recycled - then the association is
@@ -74,7 +74,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tmpfs_subr.c,v 1.89 2013/11/21 14:39:09 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tmpfs_subr.c,v 1.90 2013/11/23 16:35:32 rmind Exp $");
#include <sys/param.h>
#include <sys/cprng.h>
@@ -132,7 +132,6 @@ tmpfs_alloc_node(tmpfs_mount_t *tmp, enu
/* Generic initialization. */
nnode->tn_type = type;
nnode->tn_size = 0;
- nnode->tn_status = 0;
nnode->tn_flags = 0;
nnode->tn_lockf = NULL;
@@ -244,6 +243,7 @@ tmpfs_free_node(tmpfs_mount_t *tmp, tmpf
}
break;
case VDIR:
+ KASSERT(node->tn_size == 0);
KASSERT(node->tn_spec.tn_dir.tn_seq_arena == NULL);
KASSERT(TAILQ_EMPTY(&node->tn_spec.tn_dir.tn_dir));
KASSERT(node->tn_spec.tn_dir.tn_parent == NULL ||
@@ -252,6 +252,7 @@ tmpfs_free_node(tmpfs_mount_t *tmp, tmpf
default:
break;
}
+ KASSERT(node->tn_links == 0);
mutex_destroy(&node->tn_vlock);
tmpfs_node_put(tmp, node);
@@ -340,13 +341,13 @@ again:
}
/*
- * tmpfs_alloc_file: allocate a new file of specified type and adds it
+ * tmpfs_construct_node: allocate a new file of specified type and adds it
* into the parent directory.
*
* => Credentials of the caller are used.
*/
int
-tmpfs_alloc_file(vnode_t *dvp, vnode_t **vpp, struct vattr *vap,
+tmpfs_construct_node(vnode_t *dvp, vnode_t **vpp, struct vattr *vap,
struct componentname *cnp, char *target)
{
tmpfs_mount_t *tmp = VFS_TO_TMPFS(dvp->v_mount);
@@ -403,6 +404,9 @@ tmpfs_alloc_file(vnode_t *dvp, vnode_t *
/* Make node opaque if requested. */
if (cnp->cn_flags & ISWHITEOUT)
node->tn_flags |= UF_OPAQUE;
+
+ /* Update the parent's timestamps. */
+ tmpfs_update(dvp, TMPFS_UPDATE_MTIME | TMPFS_UPDATE_CTIME);
out:
vput(dvp);
return error;
@@ -452,8 +456,8 @@ tmpfs_free_dirent(tmpfs_mount_t *tmp, tm
* and attach the entry into the directory, specified by vnode.
*
* => Increases link count on the associated node.
- * => Increases link count on directory node, if our node is VDIR.
- * It is caller's responsibility to check for the LINK_MAX limit.
+ * => Increases link count on directory node if our node is VDIR.
+ * => It is caller's responsibility to check for the LINK_MAX limit.
* => Triggers kqueue events here.
*/
void
@@ -477,12 +481,14 @@ tmpfs_dir_attach(tmpfs_node_t *dnode, tm
/* Save the hint (might overwrite). */
node->tn_dirent_hint = de;
+ } else if ((dnode->tn_gen & TMPFS_WHITEOUT_BIT) == 0) {
+ /* Flag that there are whiteout entries. */
+ atomic_or_32(&dnode->tn_gen, TMPFS_WHITEOUT_BIT);
}
/* Insert the entry to the directory (parent of inode). */
TAILQ_INSERT_TAIL(&dnode->tn_spec.tn_dir.tn_dir, de, td_entries);
dnode->tn_size += sizeof(tmpfs_dirent_t);
- dnode->tn_status |= TMPFS_NODE_STATUSALL;
uvm_vnp_setsize(dvp, dnode->tn_size);
if (node != TMPFS_NODE_WHITEOUT && node->tn_type == VDIR) {
@@ -548,9 +554,7 @@ tmpfs_dir_detach(tmpfs_node_t *dnode, tm
dnode->tn_spec.tn_dir.tn_readdir_lastp = NULL;
}
TAILQ_REMOVE(&dnode->tn_spec.tn_dir.tn_dir, de, td_entries);
-
dnode->tn_size -= sizeof(tmpfs_dirent_t);
- dnode->tn_status |= TMPFS_NODE_STATUSALL;
tmpfs_dir_putseq(dnode, de);
if (dvp) {
@@ -584,7 +588,6 @@ tmpfs_dir_lookup(tmpfs_node_t *node, str
continue;
break;
}
- node->tn_status |= TMPFS_NODE_ACCESSED;
return de;
}
@@ -853,7 +856,7 @@ tmpfs_dir_getdents(tmpfs_node_t *node, s
uio->uio_offset = de ? tmpfs_dir_getseq(node, de) : TMPFS_DIRSEQ_EOF;
node->tn_spec.tn_dir.tn_readdir_lastp = de;
done:
- node->tn_status |= TMPFS_NODE_ACCESSED;
+ tmpfs_update(node->tn_vnode, TMPFS_UPDATE_ATIME);
kmem_free(dentp, sizeof(struct dirent));
if (error == EJUSTRETURN) {
@@ -921,8 +924,6 @@ tmpfs_reg_resize(struct vnode *vp, off_t
/*
* tmpfs_chflags: change flags of the given vnode.
- *
- * => Caller should perform tmpfs_update().
*/
int
tmpfs_chflags(vnode_t *vp, int flags, kauth_cred_t cred, lwp_t *l)
@@ -977,15 +978,13 @@ tmpfs_chflags(vnode_t *vp, int flags, ka
} else {
node->tn_flags = flags;
}
- node->tn_status |= TMPFS_NODE_CHANGED;
+ tmpfs_update(vp, TMPFS_UPDATE_CTIME);
VN_KNOTE(vp, NOTE_ATTRIB);
return 0;
}
/*
* tmpfs_chmod: change access mode on the given vnode.
- *
- * => Caller should perform tmpfs_update().
*/
int
tmpfs_chmod(vnode_t *vp, mode_t mode, kauth_cred_t cred, lwp_t *l)
@@ -1009,7 +1008,7 @@ tmpfs_chmod(vnode_t *vp, mode_t mode, ka
return error;
}
node->tn_mode = (mode & ALLPERMS);
- node->tn_status |= TMPFS_NODE_CHANGED;
+ tmpfs_update(vp, TMPFS_UPDATE_CTIME);
VN_KNOTE(vp, NOTE_ATTRIB);
return 0;
}
@@ -1019,7 +1018,6 @@ tmpfs_chmod(vnode_t *vp, mode_t mode, ka
*
* => At least one of uid or gid must be different than VNOVAL.
* => Attribute is unchanged for VNOVAL case.
- * => Caller should perform tmpfs_update().
*/
int
tmpfs_chown(vnode_t *vp, uid_t uid, gid_t gid, kauth_cred_t cred, lwp_t *l)
@@ -1054,7 +1052,7 @@ tmpfs_chown(vnode_t *vp, uid_t uid, gid_
}
node->tn_uid = uid;
node->tn_gid = gid;
- node->tn_status |= TMPFS_NODE_CHANGED;
+ tmpfs_update(vp, TMPFS_UPDATE_CTIME);
VN_KNOTE(vp, NOTE_ATTRIB);
return 0;
}
@@ -1066,6 +1064,8 @@ int
tmpfs_chsize(vnode_t *vp, u_quad_t size, kauth_cred_t cred, lwp_t *l)
{
tmpfs_node_t *node = VP_TO_TMPFS_NODE(vp);
+ const off_t length = size;
+ int error;
KASSERT(VOP_ISLOCKED(vp));
@@ -1096,8 +1096,19 @@ tmpfs_chsize(vnode_t *vp, u_quad_t size,
return EPERM;
}
- /* Note: tmpfs_truncate() will raise NOTE_EXTEND and NOTE_ATTRIB. */
- return tmpfs_truncate(vp, size);
+ if (length < 0) {
+ return EINVAL;
+ }
+ if (node->tn_size == length) {
+ return 0;
+ }
+
+ /* Note: tmpfs_reg_resize() will raise NOTE_EXTEND and NOTE_ATTRIB. */
+ if ((error = tmpfs_reg_resize(vp, length)) != 0) {
+ return error;
+ }
+ tmpfs_update(vp, TMPFS_UPDATE_CTIME | TMPFS_UPDATE_MTIME);
+ return 0;
}
/*
@@ -1126,75 +1137,40 @@ tmpfs_chtimes(vnode_t *vp, const struct
if (error)
return error;
- if (atime->tv_sec != VNOVAL && atime->tv_nsec != VNOVAL)
- node->tn_status |= TMPFS_NODE_ACCESSED;
-
- if (mtime->tv_sec != VNOVAL && mtime->tv_nsec != VNOVAL)
- node->tn_status |= TMPFS_NODE_MODIFIED;
-
- if (btime->tv_sec == VNOVAL && btime->tv_nsec == VNOVAL)
- btime = NULL;
-
- tmpfs_update(vp, atime, mtime, btime, 0);
+ if (atime->tv_sec != VNOVAL) {
+ node->tn_atime = *atime;
+ }
+ if (mtime->tv_sec != VNOVAL) {
+ node->tn_mtime = *mtime;
+ }
+ if (btime->tv_sec != VNOVAL) {
+ node->tn_birthtime = *btime;
+ }
VN_KNOTE(vp, NOTE_ATTRIB);
return 0;
}
/*
- * tmpfs_update: update timestamps, et al.
+ * tmpfs_update: update the timestamps as indicated by the flags.
*/
void
-tmpfs_update(vnode_t *vp, const struct timespec *acc,
- const struct timespec *mod, const struct timespec *birth, int flags)
+tmpfs_update(vnode_t *vp, unsigned tflags)
{
tmpfs_node_t *node = VP_TO_TMPFS_NODE(vp);
struct timespec nowtm;
- /* KASSERT(VOP_ISLOCKED(vp)); */
-
- if (flags & UPDATE_CLOSE) {
- /* XXX Need to do anything special? */
- }
- if ((node->tn_status & TMPFS_NODE_STATUSALL) == 0) {
+ if (tflags == 0) {
return;
}
- if (birth != NULL) {
- node->tn_birthtime = *birth;
- }
vfs_timestamp(&nowtm);
- if (node->tn_status & TMPFS_NODE_ACCESSED) {
- node->tn_atime = acc ? *acc : nowtm;
+ if (tflags & TMPFS_UPDATE_ATIME) {
+ node->tn_atime = nowtm;
}
- if (node->tn_status & TMPFS_NODE_MODIFIED) {
- node->tn_mtime = mod ? *mod : nowtm;
+ if (tflags & TMPFS_UPDATE_MTIME) {
+ node->tn_mtime = nowtm;
}
- if (node->tn_status & TMPFS_NODE_CHANGED) {
+ if (tflags & TMPFS_UPDATE_CTIME) {
node->tn_ctime = nowtm;
}
-
- node->tn_status &= ~TMPFS_NODE_STATUSALL;
-}
-
-int
-tmpfs_truncate(vnode_t *vp, off_t length)
-{
- tmpfs_node_t *node = VP_TO_TMPFS_NODE(vp);
- int error;
-
- if (length < 0) {
- error = EINVAL;
- goto out;
- }
- if (node->tn_size == length) {
- error = 0;
- goto out;
- }
- error = tmpfs_reg_resize(vp, length);
- if (error == 0) {
- node->tn_status |= TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED;
- }
-out:
- tmpfs_update(vp, NULL, NULL, NULL, 0);
- return error;
}
Index: src/sys/fs/tmpfs/tmpfs_vfsops.c
diff -u src/sys/fs/tmpfs/tmpfs_vfsops.c:1.54 src/sys/fs/tmpfs/tmpfs_vfsops.c:1.55
--- src/sys/fs/tmpfs/tmpfs_vfsops.c:1.54 Sun Nov 10 12:46:19 2013
+++ src/sys/fs/tmpfs/tmpfs_vfsops.c Sat Nov 23 16:35:32 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: tmpfs_vfsops.c,v 1.54 2013/11/10 12:46:19 rmind Exp $ */
+/* $NetBSD: tmpfs_vfsops.c,v 1.55 2013/11/23 16:35:32 rmind Exp $ */
/*
* Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc.
@@ -42,7 +42,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tmpfs_vfsops.c,v 1.54 2013/11/10 12:46:19 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tmpfs_vfsops.c,v 1.55 2013/11/23 16:35:32 rmind Exp $");
#include <sys/param.h>
#include <sys/types.h>
@@ -237,8 +237,14 @@ tmpfs_unmount(struct mount *mp, int mntf
tmpfs_dir_detach(node, de);
tmpfs_free_dirent(tmp, de);
}
+ /* Extra virtual entry (itself for the root). */
+ node->tn_links--;
}
+ /* Release the reference on root (diagnostic). */
+ node = tmp->tm_root;
+ node->tn_links--;
+
/* Second round, destroy all inodes. */
while ((node = LIST_FIRST(&tmp->tm_nodes)) != NULL) {
tmpfs_free_node(tmp, node);
Index: src/sys/fs/tmpfs/tmpfs_vnops.c
diff -u src/sys/fs/tmpfs/tmpfs_vnops.c:1.106 src/sys/fs/tmpfs/tmpfs_vnops.c:1.107
--- src/sys/fs/tmpfs/tmpfs_vnops.c:1.106 Fri Nov 8 15:44:23 2013
+++ src/sys/fs/tmpfs/tmpfs_vnops.c Sat Nov 23 16:35:32 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: tmpfs_vnops.c,v 1.106 2013/11/08 15:44:23 rmind Exp $ */
+/* $NetBSD: tmpfs_vnops.c,v 1.107 2013/11/23 16:35:32 rmind Exp $ */
/*
* Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tmpfs_vnops.c,v 1.106 2013/11/08 15:44:23 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tmpfs_vnops.c,v 1.107 2013/11/23 16:35:32 rmind Exp $");
#include <sys/param.h>
#include <sys/dirent.h>
@@ -313,7 +313,7 @@ tmpfs_create(void *v)
KASSERT(VOP_ISLOCKED(dvp));
KASSERT(vap->va_type == VREG || vap->va_type == VSOCK);
- return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
+ return tmpfs_construct_node(dvp, vpp, vap, cnp, NULL);
}
int
@@ -334,7 +334,7 @@ tmpfs_mknod(void *v)
vput(dvp);
return EINVAL;
}
- return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
+ return tmpfs_construct_node(dvp, vpp, vap, cnp, NULL);
}
int
@@ -380,8 +380,6 @@ tmpfs_close(void *v)
vnode_t *vp = ap->a_vp;
KASSERT(VOP_ISLOCKED(vp));
-
- tmpfs_update(vp, NULL, NULL, NULL, UPDATE_CLOSE);
return 0;
}
@@ -441,8 +439,6 @@ tmpfs_getattr(void *v)
vattr_null(vap);
- tmpfs_update(vp, NULL, NULL, NULL, 0);
-
vap->va_type = vp->v_type;
vap->va_mode = node->tn_mode;
vap->va_nlink = node->tn_links;
@@ -468,9 +464,6 @@ tmpfs_getattr(void *v)
return 0;
}
-#define GOODTIME(tv) ((tv)->tv_sec != VNOVAL || (tv)->tv_nsec != VNOVAL)
-/* XXX Should this operation be atomic? I think it should, but code in
- * XXX other places (e.g., ufs) doesn't seem to be... */
int
tmpfs_setattr(void *v)
{
@@ -490,31 +483,32 @@ tmpfs_setattr(void *v)
/* Abort if any unsettable attribute is given. */
if (vap->va_type != VNON || vap->va_nlink != VNOVAL ||
vap->va_fsid != VNOVAL || vap->va_fileid != VNOVAL ||
- vap->va_blocksize != VNOVAL || GOODTIME(&vap->va_ctime) ||
+ vap->va_blocksize != VNOVAL || vap->va_ctime.tv_sec != VNOVAL ||
vap->va_gen != VNOVAL || vap->va_rdev != VNOVAL ||
vap->va_bytes != VNOVAL) {
return EINVAL;
}
- if (error == 0 && (vap->va_flags != VNOVAL))
+
+ if (error == 0 && vap->va_flags != VNOVAL)
error = tmpfs_chflags(vp, vap->va_flags, cred, l);
- if (error == 0 && (vap->va_size != VNOVAL))
+ if (error == 0 && vap->va_size != VNOVAL)
error = tmpfs_chsize(vp, vap->va_size, cred, l);
if (error == 0 && (vap->va_uid != VNOVAL || vap->va_gid != VNOVAL))
error = tmpfs_chown(vp, vap->va_uid, vap->va_gid, cred, l);
- if (error == 0 && (vap->va_mode != VNOVAL))
+ if (error == 0 && vap->va_mode != VNOVAL)
error = tmpfs_chmod(vp, vap->va_mode, cred, l);
- if (error == 0 && (GOODTIME(&vap->va_atime) || GOODTIME(&vap->va_mtime)
- || GOODTIME(&vap->va_birthtime))) {
+ const bool chsometime =
+ vap->va_atime.tv_sec != VNOVAL ||
+ vap->va_mtime.tv_sec != VNOVAL ||
+ vap->va_birthtime.tv_sec != VNOVAL;
+ if (error == 0 && chsometime) {
error = tmpfs_chtimes(vp, &vap->va_atime, &vap->va_mtime,
&vap->va_birthtime, vap->va_vaflags, cred, l);
- if (error == 0)
- return 0;
}
- tmpfs_update(vp, NULL, NULL, NULL, 0);
return error;
}
@@ -543,8 +537,12 @@ tmpfs_read(void *v)
return EINVAL;
}
+ /* Note: reading zero bytes should not update atime. */
+ if (uio->uio_resid == 0) {
+ return 0;
+ }
+
node = VP_TO_TMPFS_NODE(vp);
- node->tn_status |= TMPFS_NODE_ACCESSED;
uobj = node->tn_spec.tn_reg.tn_aobj;
error = 0;
@@ -561,6 +559,8 @@ tmpfs_read(void *v)
error = ubc_uiomove(uobj, uio, len, IO_ADV_DECODE(ioflag),
UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp));
}
+
+ tmpfs_update(vp, TMPFS_UPDATE_ATIME);
return error;
}
@@ -579,7 +579,6 @@ tmpfs_write(void *v)
tmpfs_node_t *node;
struct uvm_object *uobj;
off_t oldsize;
- bool extended;
int error;
KASSERT(VOP_ISLOCKED(vp));
@@ -599,8 +598,7 @@ tmpfs_write(void *v)
uio->uio_offset = node->tn_size;
}
- extended = uio->uio_offset + uio->uio_resid > node->tn_size;
- if (extended) {
+ if (uio->uio_offset + uio->uio_resid > node->tn_size) {
error = tmpfs_reg_resize(vp, uio->uio_offset + uio->uio_resid);
if (error)
goto out;
@@ -622,8 +620,7 @@ tmpfs_write(void *v)
(void)tmpfs_reg_resize(vp, oldsize);
}
- node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED |
- (extended ? TMPFS_NODE_CHANGED : 0);
+ tmpfs_update(vp, TMPFS_UPDATE_MTIME | TMPFS_UPDATE_CTIME);
VN_KNOTE(vp, NOTE_WRITE);
out:
if (error) {
@@ -647,9 +644,8 @@ tmpfs_fsync(void *v)
} */ *ap = v;
vnode_t *vp = ap->a_vp;
- /* Nothing to do. Just update. */
+ /* Nothing to do. Should be up to date. */
KASSERT(VOP_ISLOCKED(vp));
- tmpfs_update(vp, NULL, NULL, NULL, 0);
return 0;
}
@@ -706,11 +702,14 @@ tmpfs_remove(void *v)
/*
* Remove the entry from the directory (drops the link count) and
- * destroy it or replace it with a whiteout.
- * Note: the inode referred by it will not be destroyed
- * until the vnode is reclaimed/recycled.
+ * destroy it or replace with a whiteout.
+ *
+ * Note: the inode referred by it will not be destroyed until the
+ * vnode is reclaimed/recycled.
*/
+
tmpfs_dir_detach(dnode, de);
+
if (ap->a_cnp->cn_flags & DOWHITEOUT)
tmpfs_dir_attach(dnode, de, TMPFS_NODE_WHITEOUT);
else
@@ -718,9 +717,9 @@ tmpfs_remove(void *v)
if (node->tn_links > 0) {
/* We removed a hard link. */
- node->tn_status |= TMPFS_NODE_CHANGED;
- tmpfs_update(vp, NULL, NULL, NULL, 0);
+ tmpfs_update(vp, TMPFS_UPDATE_CTIME);
}
+ tmpfs_update(dvp, TMPFS_UPDATE_MTIME | TMPFS_UPDATE_CTIME);
error = 0;
out:
/* Drop the references and unlock the vnodes. */
@@ -786,13 +785,13 @@ tmpfs_link(void *v)
* It will increase the inode link count.
*/
tmpfs_dir_attach(dnode, de, node);
+ tmpfs_update(dvp, TMPFS_UPDATE_MTIME | TMPFS_UPDATE_CTIME);
/* Update the timestamps and trigger the event. */
if (node->tn_vnode) {
VN_KNOTE(node->tn_vnode, NOTE_LINK);
}
- node->tn_status |= TMPFS_NODE_CHANGED;
- tmpfs_update(vp, NULL, NULL, NULL, 0);
+ tmpfs_update(vp, TMPFS_UPDATE_CTIME);
error = 0;
out:
VOP_UNLOCK(vp);
@@ -815,7 +814,7 @@ tmpfs_mkdir(void *v)
struct vattr *vap = ap->a_vap;
KASSERT(vap->va_type == VDIR);
- return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
+ return tmpfs_construct_node(dvp, vpp, vap, cnp, NULL);
}
int
@@ -839,19 +838,25 @@ tmpfs_rmdir(void *v)
KASSERT(node->tn_spec.tn_dir.tn_parent == dnode);
/*
- * Directories with more than two non-whiteout
- * entries ('.' and '..') cannot be removed.
+ * Directories with more than two entries ('.' and '..') cannot be
+ * removed. There may be whiteout entries, which we will destroy.
*/
if (node->tn_size > 0) {
- KASSERT(error == 0);
+ /*
+ * If never had whiteout entries, the directory is certainly
+ * not empty. Otherwise, scan for any non-whiteout entry.
+ */
+ if ((node->tn_gen & TMPFS_WHITEOUT_BIT) == 0) {
+ error = ENOTEMPTY;
+ goto out;
+ }
TAILQ_FOREACH(de, &node->tn_spec.tn_dir.tn_dir, td_entries) {
if (de->td_node != TMPFS_NODE_WHITEOUT) {
error = ENOTEMPTY;
- break;
+ goto out;
}
}
- if (error)
- goto out;
+ KASSERT(error == 0);
}
/* Lookup the directory entry (check the cached hint first). */
@@ -870,7 +875,6 @@ tmpfs_rmdir(void *v)
/* Decrement the link count for the virtual '.' entry. */
node->tn_links--;
- node->tn_status |= TMPFS_NODE_STATUSALL;
/* Detach the directory entry from the directory. */
tmpfs_dir_detach(dnode, de);
@@ -880,8 +884,9 @@ tmpfs_rmdir(void *v)
/*
* Destroy the directory entry or replace it with a whiteout.
- * Note: the inode referred by it will not be destroyed
- * until the vnode is reclaimed.
+ *
+ * Note: the inode referred by it will not be destroyed until the
+ * vnode is reclaimed.
*/
if (ap->a_cnp->cn_flags & DOWHITEOUT)
tmpfs_dir_attach(dnode, de, TMPFS_NODE_WHITEOUT);
@@ -894,7 +899,9 @@ tmpfs_rmdir(void *v)
tmpfs_dir_detach(node, de);
tmpfs_free_dirent(tmp, de);
}
+ tmpfs_update(dvp, TMPFS_UPDATE_MTIME | TMPFS_UPDATE_CTIME);
+ KASSERT(node->tn_size == 0);
KASSERT(node->tn_links == 0);
out:
/* Release the nodes. */
@@ -920,7 +927,7 @@ tmpfs_symlink(void *v)
char *target = ap->a_target;
KASSERT(vap->va_type == VLNK);
- return tmpfs_alloc_file(dvp, vpp, vap, cnp, target);
+ return tmpfs_construct_node(dvp, vpp, vap, cnp, target);
}
int
@@ -1026,7 +1033,7 @@ tmpfs_readlink(void *v)
} else {
error = 0;
}
- node->tn_status |= TMPFS_NODE_ACCESSED;
+ tmpfs_update(vp, TMPFS_UPDATE_ATIME);
return error;
}
@@ -1185,14 +1192,17 @@ tmpfs_getpages(void *v)
return EBUSY;
if ((flags & PGO_NOTIMESTAMP) == 0) {
+ u_int tflags = 0;
+
if ((vp->v_mount->mnt_flag & MNT_NOATIME) == 0)
- node->tn_status |= TMPFS_NODE_ACCESSED;
+ tflags |= TMPFS_UPDATE_ATIME;
if ((access_type & VM_PROT_WRITE) != 0) {
- node->tn_status |= TMPFS_NODE_MODIFIED;
+ tflags |= TMPFS_UPDATE_MTIME;
if (vp->v_mount->mnt_flag & MNT_RELATIME)
- node->tn_status |= TMPFS_NODE_ACCESSED;
+ tflags |= TMPFS_UPDATE_ATIME;
}
+ tmpfs_update(vp, tflags);
}
/*
@@ -1289,6 +1299,7 @@ tmpfs_whiteout(void *v)
tmpfs_free_dirent(tmp, de);
break;
}
+ tmpfs_update(dvp, TMPFS_UPDATE_MTIME | TMPFS_UPDATE_CTIME);
return 0;
}
@@ -1302,9 +1313,9 @@ tmpfs_print(void *v)
tmpfs_node_t *node = VP_TO_TMPFS_NODE(vp);
printf("tag VT_TMPFS, tmpfs_node %p, flags 0x%x, links %d\n"
- "\tmode 0%o, owner %d, group %d, size %" PRIdMAX ", status 0x%x",
+ "\tmode 0%o, owner %d, group %d, size %" PRIdMAX,
node, node->tn_flags, node->tn_links, node->tn_mode, node->tn_uid,
- node->tn_gid, (uintmax_t)node->tn_size, node->tn_status);
+ node->tn_gid, (uintmax_t)node->tn_size);
if (vp->v_type == VFIFO) {
VOCALL(fifo_vnodeop_p, VOFFSET(vop_print), v);
}