Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/fs/tmpfs/tmpfs_subr.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/fs/tmpfs/tmpfs_subr.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.23 retrieving revision 1.23.2.2 diff -u -p -r1.23 -r1.23.2.2 --- src/sys/fs/tmpfs/tmpfs_subr.c 2006/09/03 06:49:30 1.23 +++ src/sys/fs/tmpfs/tmpfs_subr.c 2007/01/12 01:04:05 1.23.2.2 @@ -1,4 +1,4 @@ -/* $NetBSD: tmpfs_subr.c,v 1.23 2006/09/03 06:49:30 christos Exp $ */ +/* $NetBSD: tmpfs_subr.c,v 1.23.2.2 2007/01/12 01:04:05 ad Exp $ */ /* * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc. @@ -42,7 +42,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: tmpfs_subr.c,v 1.23 2006/09/03 06:49:30 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: tmpfs_subr.c,v 1.23.2.2 2007/01/12 01:04:05 ad Exp $"); #include #include @@ -116,7 +116,7 @@ tmpfs_alloc_node(struct tmpfs_mount *tmp if (nnode == NULL) return ENOSPC; nnode->tn_id = tmp->tm_nodes_last++; - nnode->tn_gen = 0; + nnode->tn_gen = arc4random(); } else { nnode = LIST_FIRST(&tmp->tm_nodes_avail); LIST_REMOVE(nnode, tn_entries); @@ -155,6 +155,10 @@ tmpfs_alloc_node(struct tmpfs_mount *tmp nnode->tn_spec.tn_dir.tn_readdir_lastp = NULL; nnode->tn_links++; nnode->tn_spec.tn_dir.tn_parent->tn_links++; + if (parent != NULL) { + KASSERT(parent->tn_vnode != NULL); + VN_KNOTE(parent->tn_vnode, NOTE_LINK); + } break; case VFIFO: @@ -270,7 +274,8 @@ tmpfs_free_node(struct tmpfs_mount *tmp, * The new directory entry is returned in *de. * * The link count of node is increased by one to reflect the new object - * referencing it. + * referencing it. This takes care of notifying kqueue listeners about + * this change. * * Returns zero on success or an appropriate error code on failure. */ @@ -294,6 +299,8 @@ tmpfs_alloc_dirent(struct tmpfs_mount *t nde->td_node = node; node->tn_links++; + if (node->tn_links > 1 && node->tn_vnode != NULL) + VN_KNOTE(node->tn_vnode, NOTE_LINK); *de = nde; return 0; @@ -309,6 +316,10 @@ tmpfs_alloc_dirent(struct tmpfs_mount *t * object that referenced it. This only happens if 'node_exists' is true; * otherwise the function will not access the node referred to by the * directory entry, as it may already have been released from the outside. + * + * Interested parties (kqueue) are notified of the link count change; note + * that this can include both the node pointed to by the directory entry + * as well as its parent. */ void tmpfs_free_dirent(struct tmpfs_mount *tmp, struct tmpfs_dirent *de, @@ -321,6 +332,12 @@ tmpfs_free_dirent(struct tmpfs_mount *tm KASSERT(node->tn_links > 0); node->tn_links--; + if (node->tn_vnode != NULL) + VN_KNOTE(node->tn_vnode, node->tn_links == 0 ? + NOTE_DELETE : NOTE_LINK); + if (node->tn_type == VDIR) + VN_KNOTE(node->tn_spec.tn_dir.tn_parent->tn_vnode, + NOTE_LINK); } tmpfs_str_pool_put(&tmp->tm_str_pool, de->td_name, de->td_namelen); @@ -522,7 +539,6 @@ tmpfs_alloc_file(struct vnode *dvp, stru * insert the new node into the directory, an operation that * cannot fail. */ tmpfs_dir_attach(dvp, de); - VN_KNOTE(dvp, NOTE_WRITE); out: if (error != 0 || !(cnp->cn_flags & SAVESTART)) @@ -541,6 +557,9 @@ out: * Attaches the directory entry de to the directory represented by vp. * Note that this does not change the link count of the node pointed by * the directory entry, as this is done by tmpfs_alloc_dirent. + * + * As the "parent" directory changes, interested parties are notified of + * a write to it. */ void tmpfs_dir_attach(struct vnode *vp, struct tmpfs_dirent *de) @@ -554,6 +573,8 @@ tmpfs_dir_attach(struct vnode *vp, struc dnode->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \ TMPFS_NODE_MODIFIED; uvm_vnp_setsize(vp, dnode->tn_size); + + VN_KNOTE(vp, NOTE_WRITE); } /* --------------------------------------------------------------------- */ @@ -562,6 +583,9 @@ tmpfs_dir_attach(struct vnode *vp, struc * Detaches the directory entry de from the directory represented by vp. * Note that this does not change the link count of the node pointed by * the directory entry, as this is done by tmpfs_free_dirent. + * + * As the "parent" directory changes, interested parties are notified of + * a write to it. */ void tmpfs_dir_detach(struct vnode *vp, struct tmpfs_dirent *de) @@ -582,6 +606,8 @@ tmpfs_dir_detach(struct vnode *vp, struc dnode->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \ TMPFS_NODE_MODIFIED; uvm_vnp_setsize(vp, dnode->tn_size); + + VN_KNOTE(vp, NOTE_WRITE); } /* --------------------------------------------------------------------- */ @@ -695,7 +721,7 @@ tmpfs_dir_getdotdotdent(struct tmpfs_nod if (de == NULL) uio->uio_offset = TMPFS_DIRCOOKIE_EOF; else - uio->uio_offset = TMPFS_DIRCOOKIE(de); + uio->uio_offset = tmpfs_dircookie(de); } } @@ -720,7 +746,7 @@ tmpfs_dir_lookupbycookie(struct tmpfs_no } TAILQ_FOREACH(de, &node->tn_spec.tn_dir.tn_dir, td_entries) { - if (TMPFS_DIRCOOKIE(de) == cookie) { + if (tmpfs_dircookie(de) == cookie) { break; } } @@ -829,7 +855,7 @@ tmpfs_dir_getdents(struct tmpfs_node *no node->tn_spec.tn_dir.tn_readdir_lastp = NULL; } else { node->tn_spec.tn_dir.tn_readdir_lastn = uio->uio_offset = - TMPFS_DIRCOOKIE(de); + tmpfs_dircookie(de); node->tn_spec.tn_dir.tn_readdir_lastp = de; } @@ -845,6 +871,10 @@ tmpfs_dir_getdents(struct tmpfs_node *no * the size newsize. 'vp' must point to a vnode that represents a regular * file. 'newsize' must be positive. * + * If the file is extended, the appropriate kevent is raised. This does + * not rise a write event though because resizing is not the same as + * writing. + * * Returns zero on success or an appropriate error code on failure. */ int @@ -908,6 +938,9 @@ tmpfs_reg_resize(struct vnode *vp, off_t error = 0; + if (newsize > oldsize) + VN_KNOTE(vp, NOTE_EXTEND); + out: return error; } @@ -973,13 +1006,14 @@ tmpfs_chflags(struct vnode *vp, int flag * somewhere? */ if (kauth_cred_geteuid(cred) != node->tn_uid && (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, - &l->l_acflag))) + NULL))) return error; - if (kauth_cred_geteuid(cred) == 0) { + if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL) == 0) { /* The super-user is only allowed to change flags if the file * wasn't protected before and the securelevel is zero. */ if ((node->tn_flags & (SF_IMMUTABLE | SF_APPEND)) && - securelevel > 0) + kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_CHSYSFLAGS, + 0, NULL, NULL, NULL)) return EPERM; node->tn_flags = flags; } else { @@ -1033,9 +1067,9 @@ tmpfs_chmod(struct vnode *vp, mode_t mod * somewhere? */ if (kauth_cred_geteuid(cred) != node->tn_uid && (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, - &l->l_acflag))) + NULL))) return error; - if (kauth_cred_geteuid(cred) != 0) { + if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL) != 0) { if (vp->v_type != VDIR && (mode & S_ISTXT)) return EFTYPE; @@ -1097,7 +1131,7 @@ tmpfs_chown(struct vnode *vp, uid_t uid, (gid != node->tn_gid && !(kauth_cred_getegid(cred) == node->tn_gid || (kauth_cred_ismember_gid(cred, gid, &ismember) == 0 && ismember)))) && ((error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, - &l->l_acflag)) != 0)) + NULL)) != 0)) return error; node->tn_uid = uid; @@ -1199,7 +1233,7 @@ tmpfs_chtimes(struct vnode *vp, struct t * somewhere? */ if (kauth_cred_geteuid(cred) != node->tn_uid && (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, - &l->l_acflag)) && ((vaflags & VA_UTIMES_NULL) == 0 || + NULL)) && ((vaflags & VA_UTIMES_NULL) == 0 || (error = VOP_ACCESS(vp, VWRITE, cred, l)))) return error; @@ -1210,6 +1244,7 @@ tmpfs_chtimes(struct vnode *vp, struct t node->tn_status |= TMPFS_NODE_MODIFIED; tmpfs_update(vp, atime, mtime, 0); + VN_KNOTE(vp, NOTE_ATTRIB); KASSERT(VOP_ISLOCKED(vp)); @@ -1296,10 +1331,8 @@ tmpfs_truncate(struct vnode *vp, off_t l } error = tmpfs_reg_resize(vp, length); - if (error == 0) { - VN_KNOTE(vp, NOTE_ATTRIB | (extended ? NOTE_EXTEND : 0)); + if (error == 0) node->tn_status |= TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED; - } out: tmpfs_update(vp, NULL, NULL, 0);