summaryrefslogtreecommitdiffstats
path: root/sys/tmpfs
diff options
context:
space:
mode:
Diffstat (limited to 'sys/tmpfs')
-rw-r--r--sys/tmpfs/tmpfs.h97
-rw-r--r--sys/tmpfs/tmpfs_subr.c468
-rw-r--r--sys/tmpfs/tmpfs_vfsops.c62
-rw-r--r--sys/tmpfs/tmpfs_vnops.c255
-rw-r--r--sys/tmpfs/tmpfs_vnops.h5
5 files changed, 360 insertions, 527 deletions
diff --git a/sys/tmpfs/tmpfs.h b/sys/tmpfs/tmpfs.h
index 6f8736795e7..54916a238a1 100644
--- a/sys/tmpfs/tmpfs.h
+++ b/sys/tmpfs/tmpfs.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmpfs.h,v 1.4 2013/09/22 03:34:31 guenther Exp $ */
+/* $OpenBSD: tmpfs.h,v 1.5 2013/12/14 18:01:52 espie Exp $ */
/* $NetBSD: tmpfs.h,v 1.45 2011/09/27 01:10:43 christos Exp $ */
/*
@@ -56,6 +56,9 @@ typedef struct tmpfs_dirent {
/* Pointer to the inode this entry refers to. */
struct tmpfs_node * td_node;
+ /* Sequence number, see tmpfs_dir_getseq(). */
+ uint64_t td_seq;
+
/* Name and its length. */
char * td_name;
uint16_t td_namelen;
@@ -63,46 +66,10 @@ typedef struct tmpfs_dirent {
TAILQ_HEAD(tmpfs_dir, tmpfs_dirent);
-#if defined(_KERNEL)
-
-/* TMPFS_MAXNAMLEN can't exceed UINT16_MAX. */
-#define TMPFS_MAXNAMLEN 255
-
-#define TMPFS_DIRCOOKIE_DOT 0
-#define TMPFS_DIRCOOKIE_DOTDOT 1
-#define TMPFS_DIRCOOKIE_EOF 2
-
-/*
- * Each entry in a directory has a cookie that identifies it. Cookies
- * supersede offsets within directories, as tmpfs has no offsets as such.
- *
- * The '.', '..' and the end of directory markers have fixed cookies,
- * which cannot collide with the cookies generated by other entries.
- *
- * The cookies for the other entries are generated based on the memory
- * address of their representative meta-data structure.
- *
- * XXX: Truncating directory cookies to 31 bits now - workaround for
- * problem with Linux compat, see PR/32034.
- */
-static inline off_t
-tmpfs_dircookie(tmpfs_dirent_t *de)
-{
- off_t cookie;
-
- cookie = ((off_t)(uintptr_t)de >> 1) & 0x7FFFFFFF;
- KASSERT(cookie != TMPFS_DIRCOOKIE_DOT);
- KASSERT(cookie != TMPFS_DIRCOOKIE_DOTDOT);
- KASSERT(cookie != TMPFS_DIRCOOKIE_EOF);
-
- return cookie;
-}
-#endif
-
/*
* Internal representation of a tmpfs file system node -- inode.
*
- * This structure is splitted in two parts: one holds attributes common
+ * This structure is split in two parts: one holds attributes common
* to all file types and the other holds data that is only applicable to
* a particular type.
*
@@ -168,11 +135,13 @@ typedef struct tmpfs_node {
/* List of directory entries. */
struct tmpfs_dir tn_dir;
+ /* Last given sequence number. */
+ uint64_t tn_next_seq;
+
/*
- * Number and pointer of the last directory entry
- * returned by the readdir(3) operation.
+ * Pointer of the last directory entry returned
+ * by the readdir(3) operation.
*/
- off_t tn_readdir_lastn;
struct tmpfs_dirent * tn_readdir_lastp;
} tn_dir;
@@ -202,6 +171,29 @@ typedef struct tmpfs_node {
LIST_HEAD(tmpfs_node_list, tmpfs_node);
+
+#define TMPFS_MAXNAMLEN 255
+/* Validate maximum td_namelen length. */
+/* CTASSERT(TMPFS_MAXNAMLEN < UINT16_MAX); */
+
+/*
+ * Reserved values for the virtual entries (the first must be 0) and EOF.
+ * The start/end of the incremental range, see tmpfs_dir_getseq().
+ */
+#define TMPFS_DIRSEQ_DOT 0
+#define TMPFS_DIRSEQ_DOTDOT 1
+#define TMPFS_DIRSEQ_EOF 2
+
+#define TMPFS_DIRSEQ_START 3 /* inclusive */
+#define TMPFS_DIRSEQ_END UINT64_MAX /* exclusive */
+
+/* Mark to indicate that the number is not set. */
+#define TMPFS_DIRSEQ_NONE UINT64_MAX
+
+/* Can we still append entries to a directory? */
+#define TMPFS_DIRSEQ_FULL(dnode) \
+ ((dnode)->tn_spec.tn_dir.tn_next_seq == TMPFS_DIRSEQ_END)
+
/* Status flags. */
#define TMPFS_NODE_ACCESSED 0x01
#define TMPFS_NODE_MODIFIED 0x02
@@ -223,9 +215,6 @@ LIST_HEAD(tmpfs_node_list, tmpfs_node);
#define TMPFS_NODE_GEN(node) \
((node)->tn_gen & TMPFS_NODE_GEN_MASK)
-/* White-out inode indicator. */
-#define TMPFS_NODE_WHITEOUT ((tmpfs_node_t *)-1)
-
/*
* Internal representation of a tmpfs mount point.
*/
@@ -233,6 +222,8 @@ typedef struct tmpfs_mount {
/* Limit and number of bytes in use by the file system. */
uint64_t tm_mem_limit;
uint64_t tm_bytes_used;
+ /* Highest allocated inode number. */
+ uint64_t tm_highest_inode;
struct rwlock tm_acc_lock;
/* Pointer to the root inode. */
@@ -276,15 +267,15 @@ int tmpfs_vnode_get(struct mount *, tmpfs_node_t *, struct vnode **);
int tmpfs_alloc_dirent(tmpfs_mount_t *, const char *, uint16_t,
tmpfs_dirent_t **);
void tmpfs_free_dirent(tmpfs_mount_t *, tmpfs_dirent_t *);
-void tmpfs_dir_attach(struct vnode *, tmpfs_dirent_t *, tmpfs_node_t *);
-void tmpfs_dir_detach(struct vnode *, tmpfs_dirent_t *);
+void tmpfs_dir_attach(tmpfs_node_t *, tmpfs_dirent_t *,
+ tmpfs_node_t *);
+void tmpfs_dir_detach(tmpfs_node_t *, tmpfs_dirent_t *);
tmpfs_dirent_t *tmpfs_dir_lookup(tmpfs_node_t *, struct componentname *);
tmpfs_dirent_t *tmpfs_dir_cached(tmpfs_node_t *);
-int tmpfs_dir_getdotdent(tmpfs_node_t *, struct uio *);
-int tmpfs_dir_getdotdotdent(tmpfs_node_t *, struct uio *);
-tmpfs_dirent_t *tmpfs_dir_lookupbycookie(tmpfs_node_t *, off_t);
+uint64_t tmpfs_dir_getseq(tmpfs_node_t *, tmpfs_dirent_t *);
+tmpfs_dirent_t *tmpfs_dir_lookupbyseq(tmpfs_node_t *, off_t);
int tmpfs_dir_getdents(tmpfs_node_t *, struct uio *);
int tmpfs_reg_resize(struct vnode *, off_t);
@@ -332,12 +323,10 @@ int tmpfs_strname_neqlen(struct componentname *, struct componentname *);
* Ensures that the node pointed by 'node' is a directory and that its
* contents are consistent with respect to directories.
*/
-#define TMPFS_VALIDATE_DIR(node) \
+#define TMPFS_VALIDATE_DIR(node) \
+ KASSERT((node)->tn_vnode == NULL || VOP_ISLOCKED((node)->tn_vnode)); \
KASSERT((node)->tn_type == VDIR); \
- KASSERT((node)->tn_size % sizeof(tmpfs_dirent_t) == 0); \
- KASSERT((node)->tn_spec.tn_dir.tn_readdir_lastp == NULL || \
- tmpfs_dircookie((node)->tn_spec.tn_dir.tn_readdir_lastp) == \
- (node)->tn_spec.tn_dir.tn_readdir_lastn);
+ KASSERT((node)->tn_size % sizeof(tmpfs_dirent_t) == 0);
/*
* Memory management stuff.
diff --git a/sys/tmpfs/tmpfs_subr.c b/sys/tmpfs/tmpfs_subr.c
index 2955dead36c..d72edbd2eab 100644
--- a/sys/tmpfs/tmpfs_subr.c
+++ b/sys/tmpfs/tmpfs_subr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmpfs_subr.c,v 1.4 2013/09/22 03:34:31 guenther Exp $ */
+/* $OpenBSD: tmpfs_subr.c,v 1.5 2013/12/14 18:01:52 espie Exp $ */
/* $NetBSD: tmpfs_subr.c,v 1.79 2012/03/13 18:40:50 elad Exp $ */
/*
@@ -90,13 +90,19 @@ __KERNEL_RCSID(0, "$NetBSD: tmpfs_subr.c,v 1.79 2012/03/13 18:40:50 elad Exp $")
#include <sys/stat.h>
#include <sys/systm.h>
#include <sys/vnode.h>
-#include <sys/malloc.h>
#include <uvm/uvm.h>
+#include <dev/rndvar.h>
+
#include <tmpfs/tmpfs.h>
#include <tmpfs/tmpfs_vnops.h>
+
+/* Local functions. */
+void tmpfs_dir_putseq(tmpfs_node_t *, tmpfs_dirent_t *);
+int tmpfs_dir_getdotents(tmpfs_node_t *, struct dirent *, struct uio *);
+
/*
* tmpfs_alloc_node: allocate a new inode of a specified type and
* insert it into the list of specified mount point.
@@ -118,19 +124,22 @@ tmpfs_alloc_node(tmpfs_mount_t *tmp, enum vtype type, uid_t uid, gid_t gid,
nnode->tn_vnode = NULL;
nnode->tn_dirent_hint = NULL;
- /*
- * XXX Where the pool is backed by a map larger than (4GB *
- * sizeof(*nnode)), this may produce duplicate inode numbers
- * for applications that do not understand 64-bit ino_t.
- */
- nnode->tn_id = (ino_t)((uintptr_t)nnode / sizeof(*nnode));
- nnode->tn_gen = TMPFS_NODE_GEN_MASK & random();
+ rw_enter_write(&tmp->tm_acc_lock);
+ nnode->tn_id = ++tmp->tm_highest_inode;
+ if (nnode->tn_id == 0) {
+ --tmp->tm_highest_inode;
+ rw_exit_write(&tmp->tm_acc_lock);
+ tmpfs_node_put(tmp, nnode);
+ return ENOSPC;
+ }
+ rw_exit_write(&tmp->tm_acc_lock);
/* Generic initialization. */
nnode->tn_type = type;
nnode->tn_size = 0;
nnode->tn_flags = 0;
nnode->tn_lockf = NULL;
+ nnode->tn_gen = TMPFS_NODE_GEN_MASK & arc4random();
nanotime(&nnode->tn_atime);
nnode->tn_birthtime = nnode->tn_atime;
@@ -156,7 +165,7 @@ tmpfs_alloc_node(tmpfs_mount_t *tmp, enum vtype type, uid_t uid, gid_t gid,
/* Directory. */
TAILQ_INIT(&nnode->tn_spec.tn_dir.tn_dir);
nnode->tn_spec.tn_dir.tn_parent = NULL;
- nnode->tn_spec.tn_dir.tn_readdir_lastn = 0;
+ nnode->tn_spec.tn_dir.tn_next_seq = TMPFS_DIRSEQ_START;
nnode->tn_spec.tn_dir.tn_readdir_lastp = NULL;
/* Extra link count for the virtual '.' entry. */
@@ -244,16 +253,19 @@ tmpfs_free_node(tmpfs_mount_t *tmp, tmpfs_node_t *node)
}
break;
case VDIR:
- /*
- * KASSERT(TAILQ_EMPTY(&node->tn_spec.tn_dir.tn_dir));
- * KASSERT(node->tn_spec.tn_dir.tn_parent == NULL ||
- * node == tmp->tm_root);
- */
+ KASSERT(TAILQ_EMPTY(&node->tn_spec.tn_dir.tn_dir));
+ KASSERT(node->tn_spec.tn_dir.tn_parent == NULL ||
+ node == tmp->tm_root);
break;
default:
break;
}
+ rw_enter_write(&tmp->tm_acc_lock);
+ if (node->tn_id == tmp->tm_highest_inode)
+ --tmp->tm_highest_inode;
+ rw_exit_write(&tmp->tm_acc_lock);
+
/* mutex_destroy(&node->tn_nlock); */
tmpfs_node_put(tmp, node);
}
@@ -383,6 +395,11 @@ tmpfs_alloc_file(struct vnode *dvp, struct vnode **vpp, struct vattr *vap,
KASSERT(dnode->tn_links < LINK_MAX);
}
+ if (TMPFS_DIRSEQ_FULL(dnode)) {
+ error = ENOSPC;
+ goto out;
+ }
+
/* Allocate a node that represents the new file. */
error = tmpfs_alloc_node(tmp, vap->va_type, cnp->cn_cred->cr_uid,
dnode->tn_gid, vap->va_mode, target, vap->va_rdev, &node);
@@ -405,24 +422,8 @@ tmpfs_alloc_file(struct vnode *dvp, struct vnode **vpp, struct vattr *vap,
goto out;
}
-#if 0 /* ISWHITEOUT doesn't exist in OpenBSD */
- /* Remove whiteout before adding the new entry. */
- if (cnp->cn_flags & ISWHITEOUT) {
- wde = tmpfs_dir_lookup(dnode, cnp);
- KASSERT(wde != NULL && wde->td_node == TMPFS_NODE_WHITEOUT);
- tmpfs_dir_detach(dvp, wde);
- tmpfs_free_dirent(tmp, wde);
- }
-#endif
-
/* Associate inode and attach the entry into the directory. */
- tmpfs_dir_attach(dvp, de, node);
-
-#if 0 /* ISWHITEOUT doesn't exist in OpenBSD */
- /* Make node opaque if requested. */
- if (cnp->cn_flags & ISWHITEOUT)
- node->tn_flags |= UF_OPAQUE;
-#endif
+ tmpfs_dir_attach(dnode, de, node);
out:
if (error == 0 && (cnp->cn_flags & SAVESTART) == 0)
@@ -452,6 +453,7 @@ tmpfs_alloc_dirent(tmpfs_mount_t *tmp, const char *name, uint16_t len,
}
nde->td_namelen = len;
memcpy(nde->td_name, name, len);
+ nde->td_seq = TMPFS_DIRSEQ_NONE;
*de = nde;
return 0;
@@ -464,7 +466,8 @@ void
tmpfs_free_dirent(tmpfs_mount_t *tmp, tmpfs_dirent_t *de)
{
- /* KASSERT(de->td_node == NULL); */
+ KASSERT(de->td_node == NULL);
+ KASSERT(de->td_seq == TMPFS_DIRSEQ_NONE);
tmpfs_strname_free(tmp, de->td_name, de->td_namelen);
tmpfs_dirent_put(tmp, de);
}
@@ -479,22 +482,25 @@ tmpfs_free_dirent(tmpfs_mount_t *tmp, tmpfs_dirent_t *de)
* => Triggers kqueue events here.
*/
void
-tmpfs_dir_attach(struct vnode *dvp, tmpfs_dirent_t *de, tmpfs_node_t *node)
+tmpfs_dir_attach(tmpfs_node_t *dnode, tmpfs_dirent_t *de, tmpfs_node_t *node)
{
- tmpfs_node_t *dnode = VP_TO_TMPFS_DIR(dvp);
+ struct vnode *dvp = dnode->tn_vnode;
int events = NOTE_WRITE;
+ KASSERT(dvp != NULL);
KASSERT(VOP_ISLOCKED(dvp));
+ /* Get a new sequence number. */
+ KASSERT(de->td_seq == TMPFS_DIRSEQ_NONE);
+ de->td_seq = tmpfs_dir_getseq(dnode, de);
+
/* Associate directory entry and the inode. */
de->td_node = node;
- if (node != TMPFS_NODE_WHITEOUT) {
- KASSERT(node->tn_links < LINK_MAX);
- node->tn_links++;
+ KASSERT(node->tn_links < LINK_MAX);
+ node->tn_links++;
- /* Save the hint (might overwrite). */
- node->tn_dirent_hint = de;
- }
+ /* Save the hint (might overwrite). */
+ node->tn_dirent_hint = de;
/* Insert the entry to the directory (parent of inode). */
TAILQ_INSERT_TAIL(&dnode->tn_spec.tn_dir.tn_dir, de, td_entries);
@@ -502,7 +508,7 @@ tmpfs_dir_attach(struct vnode *dvp, tmpfs_dirent_t *de, tmpfs_node_t *node)
tmpfs_update(dnode, TMPFS_NODE_STATUSALL);
uvm_vnp_setsize(dvp, dnode->tn_size);
- if (node != TMPFS_NODE_WHITEOUT && node->tn_type == VDIR) {
+ if (node->tn_type == VDIR) {
/* Set parent. */
KASSERT(node->tn_spec.tn_dir.tn_parent == NULL);
node->tn_spec.tn_dir.tn_parent = dnode;
@@ -526,52 +532,49 @@ tmpfs_dir_attach(struct vnode *dvp, tmpfs_dirent_t *de, tmpfs_node_t *node)
* => Triggers kqueue events here.
*/
void
-tmpfs_dir_detach(struct vnode *dvp, tmpfs_dirent_t *de)
+tmpfs_dir_detach(tmpfs_node_t *dnode, tmpfs_dirent_t *de)
{
- tmpfs_node_t *dnode = VP_TO_TMPFS_DIR(dvp);
tmpfs_node_t *node = de->td_node;
+ struct vnode *vp, *dvp = dnode->tn_vnode;
int events = NOTE_WRITE;
- KASSERT(VOP_ISLOCKED(dvp));
+ KASSERT(dvp == NULL || VOP_ISLOCKED(dvp));
- if (node != TMPFS_NODE_WHITEOUT) {
- struct vnode *vp = node->tn_vnode;
+ /* Deassociate the inode and entry. */
+ de->td_node = NULL;
+ node->tn_dirent_hint = NULL;
+ KASSERT(node->tn_links > 0);
+ node->tn_links--;
+ if ((vp = node->tn_vnode) != NULL) {
KASSERT(VOP_ISLOCKED(vp));
+ VN_KNOTE(vp, node->tn_links ? NOTE_LINK : NOTE_DELETE);
+ }
- /* Deassociate the inode and entry. */
- de->td_node = NULL;
- node->tn_dirent_hint = NULL;
-
- KASSERT(node->tn_links > 0);
- node->tn_links--;
- if (vp) {
- VN_KNOTE(vp, node->tn_links ?
- NOTE_LINK : NOTE_DELETE);
- }
-
- /* If directory - decrease the link count of parent. */
- if (node->tn_type == VDIR) {
- KASSERT(node->tn_spec.tn_dir.tn_parent == dnode);
- node->tn_spec.tn_dir.tn_parent = NULL;
+ /* If directory - decrease the link count of parent. */
+ if (node->tn_type == VDIR) {
+ KASSERT(node->tn_spec.tn_dir.tn_parent == dnode);
+ node->tn_spec.tn_dir.tn_parent = NULL;
- KASSERT(dnode->tn_links > 0);
- dnode->tn_links--;
- events |= NOTE_LINK;
- }
+ KASSERT(dnode->tn_links > 0);
+ dnode->tn_links--;
+ events |= NOTE_LINK;
}
/* Remove the entry from the directory. */
if (dnode->tn_spec.tn_dir.tn_readdir_lastp == de) {
- dnode->tn_spec.tn_dir.tn_readdir_lastn = 0;
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);
- tmpfs_update(dnode, TMPFS_NODE_STATUSALL);
- uvm_vnp_setsize(dvp, dnode->tn_size);
- VN_KNOTE(dvp, events);
+ tmpfs_update(dnode, TMPFS_NODE_MODIFIED | TMPFS_NODE_CHANGED);
+ tmpfs_dir_putseq(dnode, de);
+ if (dvp) {
+ tmpfs_update(dnode, 0);
+ uvm_vnp_setsize(dvp, dnode->tn_size);
+ VN_KNOTE(dvp, events);
+ }
}
/*
@@ -605,7 +608,7 @@ tmpfs_dir_lookup(tmpfs_node_t *node, struct componentname *cnp)
/*
* tmpfs_dir_cached: get a cached directory entry if it is valid. Used to
- * avoid unnecessary tmpds_dir_lookup().
+ * avoid unnecessary tmpfs_dir_lookup().
*
* => The vnode must be locked.
*/
@@ -629,106 +632,122 @@ tmpfs_dir_cached(tmpfs_node_t *node)
}
/*
- * tmpfs_dir_getdotdent: helper function for tmpfs_readdir. Creates a
- * '.' entry for the given directory and returns it in the uio space.
+ * tmpfs_dir_getseq: get a per-directory sequence number for the entry.
*/
-int
-tmpfs_dir_getdotdent(tmpfs_node_t *node, struct uio *uio)
+uint64_t
+tmpfs_dir_getseq(tmpfs_node_t *dnode, tmpfs_dirent_t *de)
{
- struct dirent *dentp;
- int error;
+ uint64_t seq = de->td_seq;
- TMPFS_VALIDATE_DIR(node);
- KASSERT(uio->uio_offset == TMPFS_DIRCOOKIE_DOT);
-
- /* dentp = kmem_alloc(sizeof(struct dirent), KM_SLEEP); */
- dentp = malloc(sizeof(struct dirent), M_TEMP, M_WAITOK);
- dentp->d_fileno = node->tn_id;
- dentp->d_off = TMPFS_DIRCOOKIE_DOTDOT;
- dentp->d_type = DT_DIR;
- dentp->d_namlen = 1;
- dentp->d_name[0] = '.';
- dentp->d_name[1] = '\0';
- dentp->d_reclen = DIRENT_SIZE(dentp);
-
- if (dentp->d_reclen > uio->uio_resid)
- error = -1;
- else {
- error = uiomove(dentp, dentp->d_reclen, uio);
- if (error == 0)
- uio->uio_offset = TMPFS_DIRCOOKIE_DOTDOT;
+ TMPFS_VALIDATE_DIR(dnode);
+
+ if (__predict_true(seq != TMPFS_DIRSEQ_NONE)) {
+ /* Already set. */
+ KASSERT(seq >= TMPFS_DIRSEQ_START);
+ return seq;
+ }
+
+ /*
+ * The "." and ".." and the end-of-directory have reserved numbers.
+ * The other sequence numbers are allocated incrementally.
+ */
+
+ seq = dnode->tn_spec.tn_dir.tn_next_seq;
+ KASSERT(seq >= TMPFS_DIRSEQ_START);
+ KASSERT(seq < TMPFS_DIRSEQ_END);
+ dnode->tn_spec.tn_dir.tn_next_seq++;
+ return seq;
+}
+
+void
+tmpfs_dir_putseq(tmpfs_node_t *dnode, tmpfs_dirent_t *de)
+{
+ uint64_t seq = de->td_seq;
+
+ TMPFS_VALIDATE_DIR(dnode);
+ KASSERT(seq == TMPFS_DIRSEQ_NONE || seq >= TMPFS_DIRSEQ_START);
+ KASSERT(seq == TMPFS_DIRSEQ_NONE || seq < TMPFS_DIRSEQ_END);
+
+ de->td_seq = TMPFS_DIRSEQ_NONE;
+
+ /* Empty? We can reset. */
+ if (dnode->tn_size == 0) {
+ dnode->tn_spec.tn_dir.tn_next_seq = TMPFS_DIRSEQ_START;
+ } else if (seq != TMPFS_DIRSEQ_NONE &&
+ seq == dnode->tn_spec.tn_dir.tn_next_seq - 1) {
+ dnode->tn_spec.tn_dir.tn_next_seq--;
}
- tmpfs_update(node, TMPFS_NODE_ACCESSED);
- /* kmem_free(dentp, sizeof(struct dirent)); */
- free(dentp, M_TEMP);
- return error;
}
/*
- * tmpfs_dir_getdotdotdent: helper function for tmpfs_readdir. Creates a
- * '..' entry for the given directory and returns it in the uio space.
+ * tmpfs_dir_lookupbyseq: lookup a directory entry by the sequence number.
*/
-int
-tmpfs_dir_getdotdotdent(tmpfs_node_t *node, struct uio *uio)
+tmpfs_dirent_t *
+tmpfs_dir_lookupbyseq(tmpfs_node_t *node, off_t seq)
{
- struct dirent *dentp;
- tmpfs_dirent_t *de;
- off_t next;
- int error;
+ tmpfs_dirent_t *de = node->tn_spec.tn_dir.tn_readdir_lastp;
TMPFS_VALIDATE_DIR(node);
- KASSERT(uio->uio_offset == TMPFS_DIRCOOKIE_DOTDOT);
- de = TAILQ_FIRST(&node->tn_spec.tn_dir.tn_dir);
- if (de == NULL)
- next = TMPFS_DIRCOOKIE_EOF;
- else
- next = tmpfs_dircookie(de);
-
- /* dentp = kmem_alloc(sizeof(struct dirent), KM_SLEEP); */
- dentp = malloc(sizeof(struct dirent), M_TEMP, M_WAITOK);
- dentp->d_fileno = node->tn_spec.tn_dir.tn_parent->tn_id;
- dentp->d_off = next;
- dentp->d_type = DT_DIR;
- dentp->d_namlen = 2;
- dentp->d_name[0] = '.';
- dentp->d_name[1] = '.';
- dentp->d_name[2] = '\0';
- dentp->d_reclen = DIRENT_SIZE(dentp);
-
- if (dentp->d_reclen > uio->uio_resid)
- error = -1;
- else {
- error = uiomove(dentp, dentp->d_reclen, uio);
- if (error == 0)
- uio->uio_offset = next;
+ /*
+ * First, check the cache. If does not match - perform a lookup.
+ */
+ if (de && de->td_seq == seq) {
+ KASSERT(de->td_seq >= TMPFS_DIRSEQ_START);
+ KASSERT(de->td_seq != TMPFS_DIRSEQ_NONE);
+ return de;
}
- tmpfs_update(node, TMPFS_NODE_ACCESSED);
- /* kmem_free(dentp, sizeof(struct dirent)); */
- free(dentp, M_TEMP);
- return error;
+
+ TAILQ_FOREACH(de, &node->tn_spec.tn_dir.tn_dir, td_entries) {
+ KASSERT(de->td_seq >= TMPFS_DIRSEQ_START);
+ KASSERT(de->td_seq != TMPFS_DIRSEQ_NONE);
+ if (de->td_seq == seq)
+ return de;
+ }
+ return NULL;
}
/*
- * tmpfs_dir_lookupbycookie: lookup a directory entry by associated cookie.
+ * tmpfs_dir_getdotents: helper function for tmpfs_readdir() to get the
+ * dot meta entries, that is, "." or "..". Copy it to the UIO space.
*/
-tmpfs_dirent_t *
-tmpfs_dir_lookupbycookie(tmpfs_node_t *node, off_t cookie)
+int
+tmpfs_dir_getdotents(tmpfs_node_t *node, struct dirent *dp, struct uio *uio)
{
tmpfs_dirent_t *de;
+ off_t next = 0;
+ int error;
- KASSERT(VOP_ISLOCKED(node->tn_vnode));
+ switch (uio->uio_offset) {
+ case TMPFS_DIRSEQ_DOT:
+ dp->d_fileno = node->tn_id;
+ strlcpy(dp->d_name, ".", sizeof(dp->d_name));
+ next = TMPFS_DIRSEQ_DOTDOT;
+ break;
+ case TMPFS_DIRSEQ_DOTDOT:
+ dp->d_fileno = node->tn_spec.tn_dir.tn_parent->tn_id;
+ strlcpy(dp->d_name, "..", sizeof(dp->d_name));
+ de = TAILQ_FIRST(&node->tn_spec.tn_dir.tn_dir);
+ next = de ? tmpfs_dir_getseq(node, de) : TMPFS_DIRSEQ_EOF;
+ break;
+ default:
+ KASSERT(false);
+ }
+ dp->d_type = DT_DIR;
+ dp->d_namlen = strlen(dp->d_name);
+ dp->d_reclen = DIRENT_SIZE(dp);
+ dp->d_off = next;
- if (cookie == node->tn_spec.tn_dir.tn_readdir_lastn &&
- node->tn_spec.tn_dir.tn_readdir_lastp != NULL) {
- return node->tn_spec.tn_dir.tn_readdir_lastp;
+ if (dp->d_reclen > uio->uio_resid) {
+ return EJUSTRETURN;
}
- TAILQ_FOREACH(de, &node->tn_spec.tn_dir.tn_dir, td_entries) {
- if (tmpfs_dircookie(de) == cookie) {
- break;
- }
+
+ if ((error = uiomove(dp, dp->d_reclen, uio)) != 0) {
+ return error;
}
- return de;
+
+ uio->uio_offset = next;
+ return error;
}
/*
@@ -741,109 +760,104 @@ int
tmpfs_dir_getdents(tmpfs_node_t *node, struct uio *uio)
{
tmpfs_dirent_t *de, *next_de;
- struct dirent *dentp;
- off_t cookie, next_cookie;
- int error;
+ struct dirent dent;
+ int error = 0;
KASSERT(VOP_ISLOCKED(node->tn_vnode));
TMPFS_VALIDATE_DIR(node);
+ memset(&dent, 0, sizeof(dent));
- /*
- * Locate the first directory entry we have to return. We have cached
- * the last readdir in the node, so use those values if appropriate.
- * Otherwise do a linear scan to find the requested entry.
- */
- cookie = uio->uio_offset;
- KASSERT(cookie != TMPFS_DIRCOOKIE_DOT);
- KASSERT(cookie != TMPFS_DIRCOOKIE_DOTDOT);
- if (cookie == TMPFS_DIRCOOKIE_EOF) {
- return 0;
- } else {
- de = tmpfs_dir_lookupbycookie(node, cookie);
+ if (uio->uio_offset == TMPFS_DIRSEQ_DOT) {
+ if ((error = tmpfs_dir_getdotents(node, &dent, uio)) != 0) {
+ goto done;
+ }
+ }
+ if (uio->uio_offset == TMPFS_DIRSEQ_DOTDOT) {
+ if ((error = tmpfs_dir_getdotents(node, &dent, uio)) != 0) {
+ goto done;
+ }
}
+ /* Done if we reached the end. */
+ if (uio->uio_offset == TMPFS_DIRSEQ_EOF) {
+ goto done;
+ }
+
+ /* Locate the directory entry given by the given sequence number. */
+ de = tmpfs_dir_lookupbyseq(node, uio->uio_offset);
if (de == NULL) {
- return EINVAL;
+ error = EINVAL;
+ goto done;
}
/*
- * Read as much entries as possible; i.e., until we reach the end
- * of the directory or we exhaust uio space.
+ * Read as many entries as possible; i.e., until we reach the end
+ * of the directory or we exhaust UIO space.
*/
- /* dentp = kmem_alloc(sizeof(struct dirent), KM_SLEEP); */
- dentp = malloc(sizeof(struct dirent), M_TEMP, M_WAITOK);
do {
- /*
- * Create a dirent structure representing the current
- * inode and fill it.
- */
- if (de->td_node == TMPFS_NODE_WHITEOUT || 0) {
- dentp->d_fileno = 1;
- /* dentp->d_type = DT_WHT; */
- } else {
- dentp->d_fileno = de->td_node->tn_id;
- switch (de->td_node->tn_type) {
- case VBLK:
- dentp->d_type = DT_BLK;
- break;
- case VCHR:
- dentp->d_type = DT_CHR;
- break;
- case VDIR:
- dentp->d_type = DT_DIR;
- break;
- case VFIFO:
- dentp->d_type = DT_FIFO;
- break;
- case VLNK:
- dentp->d_type = DT_LNK;
- break;
- case VREG:
- dentp->d_type = DT_REG;
- break;
- case VSOCK:
- dentp->d_type = DT_SOCK;
- break;
- default:
- KASSERT(0);
- }
+ dent.d_fileno = de->td_node->tn_id;
+ switch (de->td_node->tn_type) {
+ case VBLK:
+ dent.d_type = DT_BLK;
+ break;
+ case VCHR:
+ dent.d_type = DT_CHR;
+ break;
+ case VDIR:
+ dent.d_type = DT_DIR;
+ break;
+ case VFIFO:
+ dent.d_type = DT_FIFO;
+ break;
+ case VLNK:
+ dent.d_type = DT_LNK;
+ break;
+ case VREG:
+ dent.d_type = DT_REG;
+ break;
+ case VSOCK:
+ dent.d_type = DT_SOCK;
+ break;
+ default:
+ KASSERT(0);
}
- dentp->d_namlen = de->td_namelen;
- KASSERT(de->td_namelen < sizeof(dentp->d_name));
- memcpy(dentp->d_name, de->td_name, de->td_namelen);
- dentp->d_name[de->td_namelen] = '\0';
- dentp->d_reclen = DIRENT_SIZE(dentp);
+ dent.d_namlen = de->td_namelen;
+ KASSERT(de->td_namelen < sizeof(dent.d_name));
+ memcpy(dent.d_name, de->td_name, de->td_namelen);
+ dent.d_name[de->td_namelen] = '\0';
+ dent.d_reclen = DIRENT_SIZE(&dent);
next_de = TAILQ_NEXT(de, td_entries);
if (next_de == NULL)
- next_cookie = TMPFS_DIRCOOKIE_EOF;
+ dent.d_off = TMPFS_DIRSEQ_EOF;
else
- next_cookie = tmpfs_dircookie(next_de);
- dentp->d_off = next_cookie;
+ dent.d_off = tmpfs_dir_getseq(node, next_de);
- /* Stop reading if the directory entry we are treating is
- * bigger than the amount of data that can be returned. */
- if (dentp->d_reclen > uio->uio_resid) {
- error = -1;
+ if (dent.d_reclen > uio->uio_resid) {
+ /* Exhausted UIO space. */
+ error = EJUSTRETURN;
break;
}
- /*
- * Copy the new dirent structure into the output buffer and
- * advance pointers.
- */
- error = uiomove(dentp, dentp->d_reclen, uio);
- if (error == 0) {
- de = next_de;
- cookie = next_cookie;
+ /* Copy out the directory entry and continue. */
+ error = uiomove(&dent, dent.d_reclen, uio);
+ if (error) {
+ break;
}
- } while (error == 0 && uio->uio_resid > 0 && de != NULL);
+ de = TAILQ_NEXT(de, td_entries);
+
+ } while (uio->uio_resid > 0 && de);
- /* Update the offset and cache. */
- node->tn_spec.tn_dir.tn_readdir_lastn = uio->uio_offset = cookie;
+ /* Cache the last entry or clear and mark EOF. */
+ uio->uio_offset = de ? tmpfs_dir_getseq(node, de) : TMPFS_DIRSEQ_EOF;
node->tn_spec.tn_dir.tn_readdir_lastp = de;
+done:
tmpfs_update(node, TMPFS_NODE_ACCESSED);
- /* kmem_free(dentp, sizeof(struct dirent)); */
- free(dentp, M_TEMP);
+
+ if (error == EJUSTRETURN) {
+ /* Exhausted UIO space - just return. */
+ error = 0;
+ }
+ KASSERT(error >= 0);
return error;
}
diff --git a/sys/tmpfs/tmpfs_vfsops.c b/sys/tmpfs/tmpfs_vfsops.c
index 519bb6e61e2..faf8e36192b 100644
--- a/sys/tmpfs/tmpfs_vfsops.c
+++ b/sys/tmpfs/tmpfs_vfsops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmpfs_vfsops.c,v 1.2 2013/06/03 10:37:02 espie Exp $ */
+/* $OpenBSD: tmpfs_vfsops.c,v 1.3 2013/12/14 18:01:52 espie Exp $ */
/* $NetBSD: tmpfs_vfsops.c,v 1.52 2011/09/27 01:10:43 christos Exp $ */
/*
@@ -94,7 +94,6 @@ tmpfs_mount(struct mount *mp, const char *path, void *data,
tmpfs_mount_t *tmp;
tmpfs_node_t *root;
uint64_t memlimit;
- size_t len;
uint64_t nodes;
int error;
@@ -155,6 +154,7 @@ tmpfs_mount(struct mount *mp, const char *path, void *data,
tmp->tm_nodes_max = (ino_t)nodes;
tmp->tm_nodes_cnt = 0;
+ tmp->tm_highest_inode = 1;
LIST_INIT(&tmp->tm_nodes);
rw_init(&tmp->tm_lock, "tmplk");
@@ -185,10 +185,18 @@ tmpfs_mount(struct mount *mp, const char *path, void *data,
#endif
vfs_getnewfsid(mp);
- copystr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &len);
- bzero(mp->mnt_stat.f_mntonname + len, MNAMELEN - len);
- len = strlcpy(mp->mnt_stat.f_mntfromname, "tmpfs", MNAMELEN - 1);
- bzero(mp->mnt_stat.f_mntfromname + len, MNAMELEN - len);
+ mp->mnt_stat.mount_info.tmpfs_args = args;
+
+ bzero(&mp->mnt_stat.f_mntonname, sizeof(mp->mnt_stat.f_mntonname));
+ bzero(&mp->mnt_stat.f_mntfromname, sizeof(mp->mnt_stat.f_mntfromname));
+ bzero(&mp->mnt_stat.f_mntfromspec, sizeof(mp->mnt_stat.f_mntfromspec));
+
+ strlcpy(mp->mnt_stat.f_mntonname, path,
+ sizeof(mp->mnt_stat.f_mntonname) - 1);
+ strlcpy(mp->mnt_stat.f_mntfromname, "tmpfs",
+ sizeof(mp->mnt_stat.f_mntfromname) - 1);
+ strlcpy(mp->mnt_stat.f_mntfromspec, "tmpfs",
+ sizeof(mp->mnt_stat.f_mntfromspec) - 1);
return error;
}
@@ -203,8 +211,8 @@ tmpfs_start(struct mount *mp, int flags, struct proc *p)
int
tmpfs_unmount(struct mount *mp, int mntflags, struct proc *p)
{
- tmpfs_mount_t *tmp;
- tmpfs_node_t *node;
+ tmpfs_mount_t *tmp = VFS_TO_TMPFS(mp);
+ tmpfs_node_t *node, *cnode;
int error, flags = 0;
/* Handle forced unmounts. */
@@ -216,31 +224,37 @@ tmpfs_unmount(struct mount *mp, int mntflags, struct proc *p)
if (error != 0)
return error;
- tmp = VFS_TO_TMPFS(mp);
- /* Destroy any existing inodes. */
- while ((node = LIST_FIRST(&tmp->tm_nodes)) != NULL) {
- if (node->tn_type == VDIR) {
- tmpfs_dirent_t *de;
-
- /* Destroy any directory entries. */
- de = TAILQ_FIRST(&node->tn_spec.tn_dir.tn_dir);
- while (de != NULL) {
- tmpfs_dirent_t *nde;
-
- nde = TAILQ_NEXT(de, td_entries);
- tmpfs_free_dirent(tmp, de);
- node->tn_size -= sizeof(tmpfs_dirent_t);
- de = nde;
+ /*
+ * First round, detach and destroy all directory entries.
+ * Also, clear the pointers to the vnodes - they are gone.
+ */
+ LIST_FOREACH(node, &tmp->tm_nodes, tn_entries) {
+ tmpfs_dirent_t *de;
+
+ node->tn_vnode = NULL;
+ if (node->tn_type != VDIR) {
+ continue;
+ }
+ while ((de = TAILQ_FIRST(&node->tn_spec.tn_dir.tn_dir)) != NULL) {
+ cnode = de->td_node;
+ if (cnode) {
+ cnode->tn_vnode = NULL;
}
+ tmpfs_dir_detach(node, de);
+ tmpfs_free_dirent(tmp, de);
}
- /* Removes inode from the list. */
+ }
+
+ /* Second round, destroy all inodes. */
+ while ((node = LIST_FIRST(&tmp->tm_nodes)) != NULL) {
tmpfs_free_node(tmp, node);
}
/* Throw away the tmpfs_mount structure. */
tmpfs_mntmem_destroy(tmp);
/* mutex_destroy(&tmp->tm_lock); */
+ /* kmem_free(tmp, sizeof(*tmp)); */
free(tmp, M_MISCFSMNT);
mp->mnt_data = NULL;
diff --git a/sys/tmpfs/tmpfs_vnops.c b/sys/tmpfs/tmpfs_vnops.c
index 7b9b5c883d8..ac93be1cf55 100644
--- a/sys/tmpfs/tmpfs_vnops.c
+++ b/sys/tmpfs/tmpfs_vnops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmpfs_vnops.c,v 1.9 2013/10/10 11:00:28 espie Exp $ */
+/* $OpenBSD: tmpfs_vnops.c,v 1.10 2013/12/14 18:01:52 espie Exp $ */
/* $NetBSD: tmpfs_vnops.c,v 1.100 2012/11/05 17:27:39 dholland Exp $ */
/*
@@ -216,7 +216,7 @@ tmpfs_lookup(void *v)
* Other lookup cases: perform directory scan.
*/
de = tmpfs_dir_lookup(dnode, cnp);
- if (de == NULL || de->td_node == TMPFS_NODE_WHITEOUT) {
+ if (de == NULL) {
/*
* The entry was not found in the directory. This is valid
* if we are creating or renaming an entry and are working
@@ -237,10 +237,6 @@ tmpfs_lookup(void *v)
} else {
error = ENOENT;
}
- if (de) {
- KASSERT(de->td_node == TMPFS_NODE_WHITEOUT);
- /* cnp->cn_flags |= ISWHITEOUT; */
- }
goto done;
}
@@ -721,7 +717,6 @@ tmpfs_remove(void *v)
/* Lookup the directory entry (check the cached hint first). */
de = tmpfs_dir_cached(node);
if (de == NULL) {
- tmpfs_node_t *dnode = VP_TO_TMPFS_DIR(dvp);
de = tmpfs_dir_lookup(dnode, cnp);
}
@@ -729,15 +724,12 @@ tmpfs_remove(void *v)
/*
* Remove the entry from the directory (drops the link count) and
- * destroy it or replace it with a whiteout.
+ * destroy it.
* Note: the inode referred by it will not be destroyed
* until the vnode is reclaimed/recycled.
*/
- tmpfs_dir_detach(dvp, de);
- if (0 /* ap->a_cnp->cn_flags & DOWHITEOUT */)
- tmpfs_dir_attach(dvp, de, TMPFS_NODE_WHITEOUT);
- else
- tmpfs_free_dirent(VFS_TO_TMPFS(vp->v_mount), de);
+ tmpfs_dir_detach(dnode, de);
+ tmpfs_free_dirent(VFS_TO_TMPFS(vp->v_mount), de);
if (node->tn_links > 0) {
/* We removed a hard link. */
tmpfs_update(node, TMPFS_NODE_CHANGED);
@@ -806,6 +798,11 @@ tmpfs_link(void *v)
goto out;
}
+ if (TMPFS_DIRSEQ_FULL(dnode)) {
+ error = ENOSPC;
+ goto out;
+ }
+
/* Allocate a new directory entry to represent the inode. */
error = tmpfs_alloc_dirent(VFS_TO_TMPFS(vp->v_mount),
cnp->cn_nameptr, cnp->cn_namelen, &de);
@@ -813,11 +810,11 @@ tmpfs_link(void *v)
goto out;
}
- /*
+ /*
* Insert the entry into the directory.
* It will increase the inode link count.
*/
- tmpfs_dir_attach(dvp, de, node);
+ tmpfs_dir_attach(dnode, de, node);
/* Update the timestamps and trigger the event. */
if (node->tn_vnode) {
@@ -880,16 +877,14 @@ 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.
*/
if (node->tn_size > 0) {
KASSERT(error == 0);
TAILQ_FOREACH(de, &node->tn_spec.tn_dir.tn_dir, td_entries) {
- if (de->td_node != TMPFS_NODE_WHITEOUT) {
- error = ENOTEMPTY;
- break;
- }
+ error = ENOTEMPTY;
+ break;
}
if (error)
goto out;
@@ -913,27 +908,18 @@ tmpfs_rmdir(void *v)
tmpfs_update(node, TMPFS_NODE_STATUSALL);
/* Detach the directory entry from the directory. */
- tmpfs_dir_detach(dvp, de);
+ tmpfs_dir_detach(dnode, de);
/* Purge the cache for parent. */
cache_purge(dvp);
/*
- * Destroy the directory entry or replace it with a whiteout.
+ * Destroy the directory entry.
* Note: the inode referred by it will not be destroyed
* until the vnode is reclaimed.
*/
- if (0 /* ap->a_cnp->cn_flags & DOWHITEOUT */)
- tmpfs_dir_attach(dvp, de, TMPFS_NODE_WHITEOUT);
- else
- tmpfs_free_dirent(tmp, de);
-
- /* Destroy the whiteout entries from the node. */
- while ((de = TAILQ_FIRST(&node->tn_spec.tn_dir.tn_dir)) != NULL) {
- KASSERT(de->td_node == TMPFS_NODE_WHITEOUT);
- tmpfs_dir_detach(vp, de);
- tmpfs_free_dirent(tmp, de);
- }
+ tmpfs_free_dirent(tmp, de);
+ KASSERT(TAILQ_FIRST(&node->tn_spec.tn_dir.tn_dir) == NULL);
KASSERT(node->tn_links == 0);
out:
@@ -993,35 +979,17 @@ tmpfs_readdir(void *v)
return ENOTDIR;
}
node = VP_TO_TMPFS_DIR(vp);
- if (node->tn_links == 0) {
+ /*
+ * Retrieve the directory entries, unless it is being destroyed.
+ */
+ if (node->tn_links) {
+ error = tmpfs_dir_getdents(node, uio);
+ } else {
error = 0;
- goto out;
}
- if (uio->uio_offset == TMPFS_DIRCOOKIE_DOT) {
- error = tmpfs_dir_getdotdent(node, uio);
- if (error != 0) {
- if (error == -1)
- error = 0;
- goto out;
- }
- }
- if (uio->uio_offset == TMPFS_DIRCOOKIE_DOTDOT) {
- error = tmpfs_dir_getdotdotdent(node, uio);
- if (error != 0) {
- if (error == -1)
- error = 0;
- goto out;
- }
- }
- error = tmpfs_dir_getdents(node, uio);
- if (error == -1) {
- error = 0;
- }
- KASSERT(error >= 0);
-out:
if (eofflag != NULL) {
- *eofflag = (!error && uio->uio_offset == TMPFS_DIRCOOKIE_EOF);
+ *eofflag = !error && uio->uio_offset == TMPFS_DIRSEQ_EOF;
}
return error;
}
@@ -1163,161 +1131,6 @@ tmpfs_advlock(void *v)
ap->a_fl, ap->a_flags);
}
-#if 0
-int
-tmpfs_getpages(void *v)
-{
- struct vop_getpages_args /* {
- struct vnode *a_vp;
- voff_t a_offset;
- struct vm_page **a_m;
- int *a_count;
- int a_centeridx;
- vm_prot_t a_access_type;
- int a_advice;
- int a_flags;
- } */ * const ap = v;
- struct vnode *vp = ap->a_vp;
- const voff_t offset = ap->a_offset;
- struct vm_page **pgs = ap->a_m;
- const int centeridx = ap->a_centeridx;
- const vm_prot_t access_type = ap->a_access_type;
- const int advice = ap->a_advice;
- const int flags = ap->a_flags;
- int error, npages = *ap->a_count;
- tmpfs_node_t *node;
- struct uvm_object *uobj;
-
- KASSERT(vp->v_type == VREG);
- KASSERT(mutex_owned(vp->v_interlock));
-
- node = VP_TO_TMPFS_NODE(vp);
- uobj = node->tn_spec.tn_reg.tn_aobj;
-
- /*
- * Currently, PGO_PASTEOF is not supported.
- */
- if (vp->v_size <= offset + (centeridx << PAGE_SHIFT)) {
- if ((flags & PGO_LOCKED) == 0)
- mutex_exit(vp->v_interlock);
- return EINVAL;
- }
-
- if (vp->v_size < offset + (npages << PAGE_SHIFT)) {
- npages = (round_page(vp->v_size) - offset) >> PAGE_SHIFT;
- }
-
- if ((flags & PGO_LOCKED) != 0)
- return EBUSY;
-
- if ((flags & PGO_NOTIMESTAMP) == 0) {
- if ((vp->v_mount->mnt_flag & MNT_NOATIME) == 0)
- node->tn_status |= TMPFS_NODE_ACCESSED;
-
- if ((access_type & VM_PROT_WRITE) != 0) {
- node->tn_status |= TMPFS_NODE_MODIFIED;
- if (vp->v_mount->mnt_flag & MNT_RELATIME)
- node->tn_status |= TMPFS_NODE_ACCESSED;
- }
- }
-
- /*
- * Invoke the pager.
- *
- * Clean the array of pages before. XXX: PR/32166
- * Note that vnode lock is shared with underlying UVM object.
- */
- if (pgs) {
- memset(pgs, 0, sizeof(struct vm_pages *) * npages);
- }
- KASSERT(vp->v_interlock == uobj->vmobjlock);
-
- error = (*uobj->pgops->pgo_get)(uobj, offset, pgs, &npages, centeridx,
- access_type, advice, flags | PGO_ALLPAGES);
-
-#if defined(DEBUG)
- if (!error && pgs) {
- for (int i = 0; i < npages; i++) {
- KASSERT(pgs[i] != NULL);
- }
- }
-#endif
- return error;
-}
-
-int
-tmpfs_putpages(void *v)
-{
- struct vop_putpages_args /* {
- struct vnode *a_vp;
- voff_t a_offlo;
- voff_t a_offhi;
- int a_flags;
- } */ * const ap = v;
- struct vnode *vp = ap->a_vp;
- const voff_t offlo = ap->a_offlo;
- const voff_t offhi = ap->a_offhi;
- const int flags = ap->a_flags;
- tmpfs_node_t *node;
- struct uvm_object *uobj;
- int error;
-
- KASSERT(mutex_owned(vp->v_interlock));
-
- if (vp->v_type != VREG) {
- mutex_exit(vp->v_interlock);
- return 0;
- }
-
- node = VP_TO_TMPFS_NODE(vp);
- uobj = node->tn_spec.tn_reg.tn_aobj;
-
- KASSERT(vp->v_interlock == uobj->vmobjlock);
- error = (*uobj->pgops->pgo_put)(uobj, offlo, offhi, flags);
-
- /* XXX mtime */
-
- return error;
-}
-
-int
-tmpfs_whiteout(void *v)
-{
- struct vop_whiteout_args /* {
- struct vnode *a_dvp;
- struct componentname *a_cnp;
- int a_flags;
- } */ *ap = v;
- struct vnode *dvp = ap->a_dvp;
- struct componentname *cnp = ap->a_cnp;
- const int flags = ap->a_flags;
- tmpfs_mount_t *tmp = VFS_TO_TMPFS(dvp->v_mount);
- tmpfs_dirent_t *de;
- int error;
-
- switch (flags) {
- case LOOKUP:
- break;
- case CREATE:
- error = tmpfs_alloc_dirent(tmp, cnp->cn_nameptr,
- cnp->cn_namelen, &de);
- if (error)
- return error;
- tmpfs_dir_attach(dvp, de, TMPFS_NODE_WHITEOUT);
- break;
- case DELETE:
- cnp->cn_flags &= ~DOWHITEOUT; /* when in doubt, cargo cult */
- de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(dvp), cnp);
- if (de == NULL)
- return ENOENT;
- tmpfs_dir_detach(dvp, de);
- tmpfs_free_dirent(tmp, de);
- break;
- }
- return 0;
-}
-#endif
-
int
tmpfs_print(void *v)
{
@@ -2394,8 +2207,10 @@ tmpfs_rename_attachdetach(struct tmpfs_mount *tmpfs,
if (fdvp != tdvp) {
/* tmpfs_dir_detach clobbers fde->td_node, so save it. */
struct tmpfs_node *fnode = fde->td_node;
- tmpfs_dir_detach(fdvp, fde);
- tmpfs_dir_attach(tdvp, fde, fnode);
+ tmpfs_node_t *fdnode = VP_TO_TMPFS_DIR(fdvp);
+ tmpfs_node_t *tdnode = VP_TO_TMPFS_DIR(tdvp);
+ tmpfs_dir_detach(fdnode, fde);
+ tmpfs_dir_attach(tdnode, fde, fnode);
} else if (tvp == NULL) {
/*
* We are changing the directory. tmpfs_dir_attach and
@@ -2410,6 +2225,7 @@ tmpfs_rename_attachdetach(struct tmpfs_mount *tmpfs,
* If we are replacing an existing target entry, delete it.
*/
if (tde != NULL) {
+ tmpfs_node_t *tdnode = VP_TO_TMPFS_DIR(tdvp);
KASSERT(tvp != NULL);
KASSERT(tde->td_node != NULL);
KASSERT((fvp->v_type == VDIR) == (tvp->v_type == VDIR));
@@ -2420,7 +2236,7 @@ tmpfs_rename_attachdetach(struct tmpfs_mount *tmpfs,
* the vnode will be recycled when released. */
tde->td_node->tn_links--;
}
- tmpfs_dir_detach(tdvp, tde);
+ tmpfs_dir_detach(tdnode, tde);
tmpfs_free_dirent(tmpfs, tde);
}
}
@@ -2465,7 +2281,7 @@ tmpfs_do_remove(struct tmpfs_mount *tmpfs, struct vnode *dvp,
cred->cr_uid != de->td_node->tn_uid)
return EPERM;
- tmpfs_dir_detach(dvp, de);
+ tmpfs_dir_detach(dnode, de);
tmpfs_free_dirent(tmpfs, de);
return 0;
@@ -2585,6 +2401,9 @@ tmpfs_rename_check_permitted(struct ucred *cred,
if (error)
return error;
+ if (TMPFS_DIRSEQ_FULL(tdnode))
+ return (ENOSPC);
+
error = tmpfs_check_sticky(cred, tdnode, tnode);
if (error)
return error;
diff --git a/sys/tmpfs/tmpfs_vnops.h b/sys/tmpfs/tmpfs_vnops.h
index 0862d676765..fdd0151444d 100644
--- a/sys/tmpfs/tmpfs_vnops.h
+++ b/sys/tmpfs/tmpfs_vnops.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmpfs_vnops.h,v 1.3 2013/06/04 09:11:40 espie Exp $ */
+/* $OpenBSD: tmpfs_vnops.h,v 1.4 2013/12/14 18:01:52 espie Exp $ */
/* $NetBSD: tmpfs_vnops.h,v 1.13 2011/05/24 20:17:49 rmind Exp $ */
/*
@@ -78,8 +78,5 @@ int tmpfs_print (void *);
int tmpfs_pathconf (void *);
int tmpfs_advlock (void *);
int tmpfs_bwrite (void *);
-int tmpfs_getpages (void *);
-int tmpfs_putpages (void *);
-int tmpfs_whiteout (void *);
#endif /* _TMPFS_TMPFS_VNOPS_H_ */