diff options
Diffstat (limited to 'sys/tmpfs')
-rw-r--r-- | sys/tmpfs/tmpfs.h | 97 | ||||
-rw-r--r-- | sys/tmpfs/tmpfs_subr.c | 468 | ||||
-rw-r--r-- | sys/tmpfs/tmpfs_vfsops.c | 62 | ||||
-rw-r--r-- | sys/tmpfs/tmpfs_vnops.c | 255 | ||||
-rw-r--r-- | sys/tmpfs/tmpfs_vnops.h | 5 |
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_ */ |