/* * genfs_rename_exit: Unlock everything we locked for rename. * * fdvp and tdvp must be referenced. * * On entry, everything is locked, and fvp and tvp referenced. * * On exit, everything is unlocked, and fvp and tvp are released. */ static void genfs_rename_exit(const struct genfs_rename_ops *ops, struct mount *mp, struct vnode *fdvp, struct vnode *fvp, struct vnode *tdvp, struct vnode *tvp) { (void)ops; KASSERT(ops != NULL); KASSERT(mp != NULL); KASSERT(fdvp != NULL); KASSERT(fvp != NULL); KASSERT(fdvp != fvp); KASSERT(fdvp != tvp); KASSERT(tdvp != tvp); KASSERT(tdvp != fvp); KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE); KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE); KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE); KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE)); if ((tvp != NULL) && (tvp != fvp)) VOP_UNLOCK(tvp); VOP_UNLOCK(fvp); if (tvp != NULL) vrele(tvp); if (tdvp != fdvp) VOP_UNLOCK(tdvp); vrele(fvp); VOP_UNLOCK(fdvp); }
/* * udf_gro_remove_check_permitted: check whether a remove is permitted given * our credentials. */ static int udf_gro_remove_check_permitted(struct mount *mp, kauth_cred_t cred, struct vnode *dvp, struct vnode *vp) { struct udf_node *dir_node = VTOI(dvp); struct udf_node *udf_node = VTOI(vp); mode_t dmode; uid_t duid, uid; gid_t gdummy; (void)mp; KASSERT(mp != NULL); KASSERT(dvp != NULL); KASSERT(vp != NULL); KASSERT(dvp != vp); KASSERT(dvp->v_type == VDIR); KASSERT(vp->v_type != VDIR); KASSERT(dvp->v_mount == mp); KASSERT(vp->v_mount == mp); KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); DPRINTF(CALL, ("udf_gro_remove_check_permitted called\n")); dmode = udf_getaccessmode(dir_node); udf_getownership(dir_node, &duid, &gdummy); udf_getownership(udf_node, &uid, &gdummy); return genfs_ufslike_remove_check_permitted(cred, dvp, dmode, duid, vp, uid); }
static int tmpfs_open(struct vop_open_args *v) { struct vnode *vp = v->a_vp; int mode = v->a_mode; int error; struct tmpfs_node *node; MPASS(VOP_ISLOCKED(vp)); node = VP_TO_TMPFS_NODE(vp); /* The file is still active but all its names have been removed * (e.g. by a "rmdir $(pwd)"). It cannot be opened any more as * it is about to die. */ if (node->tn_links < 1) return (ENOENT); /* If the file is marked append-only, deny write requests. */ if (node->tn_flags & APPEND && (mode & (FWRITE | O_APPEND)) == FWRITE) error = EPERM; else { error = 0; vnode_create_vobject(vp, node->tn_size, v->a_td); } MPASS(VOP_ISLOCKED(vp)); return error; }
/* * udf_gro_remove: rename an object over another link to itself, effectively * removing just the original link. */ static int udf_gro_remove(struct mount *mp, kauth_cred_t cred, struct vnode *dvp, struct componentname *cnp, void *de, struct vnode *vp) { struct udf_node *dir_node, *udf_node; KASSERT(mp != NULL); KASSERT(dvp != NULL); KASSERT(cnp != NULL); KASSERT(vp != NULL); KASSERT(dvp != vp); KASSERT(dvp->v_mount == mp); KASSERT(vp->v_mount == mp); KASSERT(dvp->v_type == VDIR); KASSERT(vp->v_type != VDIR); KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); DPRINTF(CALL, ("udf_gro_remove called\n")); dir_node = VTOI(dvp); udf_node = VTOI(vp); udf_dir_detach(dir_node->ump, dir_node, udf_node, cnp); return 0; }
/* * ulfs_gro_rename_check_possible: Check whether a rename is possible * independent of credentials. */ static int ulfs_gro_rename_check_possible(struct mount *mp, struct vnode *fdvp, struct vnode *fvp, struct vnode *tdvp, struct vnode *tvp) { (void)mp; KASSERT(mp != NULL); KASSERT(fdvp != NULL); KASSERT(fvp != NULL); KASSERT(tdvp != NULL); KASSERT(fdvp != fvp); KASSERT(fdvp != tvp); KASSERT(tdvp != fvp); KASSERT(tdvp != tvp); KASSERT(fvp != tvp); KASSERT(fdvp->v_type == VDIR); KASSERT(tdvp->v_type == VDIR); KASSERT(fdvp->v_mount == mp); KASSERT(fvp->v_mount == mp); KASSERT(tdvp->v_mount == mp); KASSERT((tvp == NULL) || (tvp->v_mount == mp)); KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE); KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE); KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE); KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE)); return genfs_ufslike_rename_check_possible( VTOI(fdvp)->i_flags, VTOI(fvp)->i_flags, VTOI(tdvp)->i_flags, (tvp? VTOI(tvp)->i_flags : 0), (tvp != NULL), IMMUTABLE, APPEND); }
/* * genfs_ufslike_remove_check_permitted: Check whether a remove is * permitted given our credentials, assuming UFS-like permission and * ownership semantics. * * Everything must be locked and referenced. */ int genfs_ufslike_remove_check_permitted(kauth_cred_t cred, struct vnode *dvp, mode_t dmode, uid_t duid, struct vnode *vp, uid_t uid) { int error; KASSERT(dvp != NULL); KASSERT(vp != NULL); KASSERT(dvp != vp); KASSERT(dvp->v_type == VDIR); KASSERT(vp->v_type != VDIR); KASSERT(dvp->v_mount == vp->v_mount); KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); /* * We need to write to the directory to remove from it. */ error = VOP_ACCESS(dvp, VWRITE, cred); if (error) return error; error = genfs_ufslike_check_sticky(cred, dmode, duid, vp, uid); if (error) return error; return 0; }
/* * ulfs_gro_remove: Rename an object over another link to itself, * effectively removing just the original link. */ static int ulfs_gro_remove(struct mount *mp, kauth_cred_t cred, struct vnode *dvp, struct componentname *cnp, void *de, struct vnode *vp) { struct ulfs_lookup_results *ulr = de; int error; KASSERT(mp != NULL); KASSERT(dvp != NULL); KASSERT(cnp != NULL); KASSERT(ulr != NULL); KASSERT(vp != NULL); KASSERT(dvp != vp); KASSERT(dvp->v_mount == mp); KASSERT(vp->v_mount == mp); KASSERT(dvp->v_type == VDIR); KASSERT(vp->v_type != VDIR); KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); KASSERT(cnp->cn_nameiop == DELETE); /* XXX ulfs_dirremove decrements vp's link count for us. */ error = ulfs_dirremove(dvp, ulr, VTOI(vp), cnp->cn_flags, 0); if (error) goto out1; VN_KNOTE(dvp, NOTE_WRITE); VN_KNOTE(vp, (VTOI(vp)->i_nlink? NOTE_LINK : NOTE_DELETE)); out1: return error; }
/* * ulfs_gro_rename_check_permitted: Check whether a rename is permitted * given our credentials. */ static int ulfs_gro_rename_check_permitted(struct mount *mp, kauth_cred_t cred, struct vnode *fdvp, struct vnode *fvp, struct vnode *tdvp, struct vnode *tvp) { (void)mp; KASSERT(mp != NULL); KASSERT(fdvp != NULL); KASSERT(fvp != NULL); KASSERT(tdvp != NULL); KASSERT(fdvp != fvp); KASSERT(fdvp != tvp); KASSERT(tdvp != fvp); KASSERT(tdvp != tvp); KASSERT(fvp != tvp); KASSERT(fdvp->v_type == VDIR); KASSERT(tdvp->v_type == VDIR); KASSERT(fdvp->v_mount == mp); KASSERT(fvp->v_mount == mp); KASSERT(tdvp->v_mount == mp); KASSERT((tvp == NULL) || (tvp->v_mount == mp)); KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE); KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE); KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE); KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE)); return genfs_ufslike_rename_check_permitted(cred, fdvp, VTOI(fdvp)->i_mode, VTOI(fdvp)->i_uid, fvp, VTOI(fvp)->i_uid, tdvp, VTOI(tdvp)->i_mode, VTOI(tdvp)->i_uid, tvp, (tvp? VTOI(tvp)->i_uid : 0)); }
/* * ext2fs_gro_remove: Rename an object over another link to itself, * effectively removing just the original link. */ static int ext2fs_gro_remove(struct mount *mp, kauth_cred_t cred, struct vnode *dvp, struct componentname *cnp, void *de, struct vnode *vp) { struct ufs_lookup_results *ulr = de; int error; (void)mp; KASSERT(mp != NULL); KASSERT(dvp != NULL); KASSERT(cnp != NULL); KASSERT(ulr != NULL); KASSERT(vp != NULL); KASSERT(dvp != vp); KASSERT(dvp->v_mount == mp); KASSERT(vp->v_mount == mp); KASSERT(dvp->v_type == VDIR); KASSERT(vp->v_type != VDIR); KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); error = ext2fs_dirremove(dvp, ulr, cnp); if (error) return error; KASSERT(0 < VTOI(vp)->i_e2fs_nlink); VTOI(vp)->i_e2fs_nlink--; VTOI(vp)->i_flag |= IN_CHANGE; VN_KNOTE(dvp, NOTE_WRITE); VN_KNOTE(vp, (VTOI(vp)->i_e2fs_nlink? NOTE_LINK : NOTE_DELETE)); return 0; }
/* * udf_gro_rename_check_possible: check whether a rename is possible * independent of credentials. */ static int udf_gro_rename_check_possible(struct mount *mp, struct vnode *fdvp, struct vnode *fvp, struct vnode *tdvp, struct vnode *tvp) { (void)mp; KASSERT(mp != NULL); KASSERT(fdvp != NULL); KASSERT(fvp != NULL); KASSERT(tdvp != NULL); KASSERT(fdvp != fvp); KASSERT(fdvp != tvp); KASSERT(tdvp != fvp); KASSERT(tdvp != tvp); KASSERT(fvp != tvp); KASSERT(fdvp->v_type == VDIR); KASSERT(tdvp->v_type == VDIR); KASSERT(fdvp->v_mount == mp); KASSERT(fvp->v_mount == mp); KASSERT(tdvp->v_mount == mp); KASSERT((tvp == NULL) || (tvp->v_mount == mp)); KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE); KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE); KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE); KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE)); DPRINTF(CALL, ("udf_gro_rename_check_possible called\n")); /* flags not implemented since they are not defined (yet) in UDF */ return 0; }
/* * udf_gro_directory_empty_p: return true if the directory vp is empty. dvp is * its parent. * * vp and dvp must be locked and referenced. */ static bool udf_gro_directory_empty_p(struct mount *mp, kauth_cred_t cred, struct vnode *vp, struct vnode *dvp) { struct udf_node *udf_node = VTOI(vp); int error, isempty; KASSERT(mp != NULL); KASSERT(vp != NULL); KASSERT(dvp != NULL); KASSERT(vp != dvp); KASSERT(vp->v_mount == mp); KASSERT(dvp->v_mount == mp); KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); DPRINTF(CALL, ("udf_gro_directory_empty_p called\n")); /* make sure our `leaf' node's hash is populated */ dirhash_get(&udf_node->dir_hash); error = udf_dirhash_fill(udf_node); if (error) { dirhash_put(udf_node->dir_hash); /* VERY unlikely, answer its not empty */ return 0; } /* check to see if the directory is empty */ isempty = dirhash_dir_isempty(udf_node->dir_hash); dirhash_put(udf_node->dir_hash); return isempty; }
/* * lfs_gro_rename: Actually perform the rename operation. Do a little * LFS bookkeeping and then defer to ulfs_gro_rename. */ static int lfs_gro_rename(struct mount *mp, kauth_cred_t cred, struct vnode *fdvp, struct componentname *fcnp, void *fde, struct vnode *fvp, struct vnode *tdvp, struct componentname *tcnp, void *tde, struct vnode *tvp) { int error; KASSERT(mp != NULL); KASSERT(fdvp != NULL); KASSERT(fcnp != NULL); KASSERT(fde != NULL); KASSERT(fvp != NULL); KASSERT(tdvp != NULL); KASSERT(tcnp != NULL); KASSERT(tde != NULL); KASSERT(fdvp != fvp); KASSERT(fdvp != tvp); KASSERT(tdvp != fvp); KASSERT(tdvp != tvp); KASSERT(fvp != tvp); KASSERT(fdvp->v_mount == mp); KASSERT(fvp->v_mount == mp); KASSERT(tdvp->v_mount == mp); KASSERT((tvp == NULL) || (tvp->v_mount == mp)); KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE); KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE); KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE); KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE)); error = lfs_set_dirop(tdvp, tvp); if (error != 0) return error; MARK_VNODE(fdvp); MARK_VNODE(fvp); error = ulfs_gro_rename(mp, cred, fdvp, fcnp, fde, fvp, tdvp, tcnp, tde, tvp); UNMARK_VNODE(fdvp); UNMARK_VNODE(fvp); UNMARK_VNODE(tdvp); if (tvp) { UNMARK_VNODE(tvp); } lfs_unset_dirop(VFSTOULFS(mp)->um_lfs, tdvp, "rename"); vrele(tdvp); if (tvp) { vrele(tvp); } return error; }
/* 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(struct vop_setattr_args *v) { struct vnode *vp = v->a_vp; struct vattr *vap = v->a_vap; struct ucred *cred = v->a_cred; struct thread *td = curthread; int error; MPASS(VOP_ISLOCKED(vp)); error = 0; /* 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 || vap->va_gen != VNOVAL || vap->va_rdev != VNOVAL || vap->va_bytes != VNOVAL) error = EINVAL; if (error == 0 && (vap->va_flags != VNOVAL)) error = tmpfs_chflags(vp, vap->va_flags, cred, td); if (error == 0 && (vap->va_size != VNOVAL)) error = tmpfs_chsize(vp, vap->va_size, cred, td); if (error == 0 && (vap->va_uid != VNOVAL || vap->va_gid != VNOVAL)) error = tmpfs_chown(vp, vap->va_uid, vap->va_gid, cred, td); if (error == 0 && (vap->va_mode != (mode_t)VNOVAL)) error = tmpfs_chmod(vp, vap->va_mode, cred, td); if (error == 0 && ((vap->va_atime.tv_sec != VNOVAL && vap->va_atime.tv_nsec != VNOVAL) || (vap->va_mtime.tv_sec != VNOVAL && vap->va_mtime.tv_nsec != VNOVAL) || (vap->va_birthtime.tv_sec != VNOVAL && vap->va_birthtime.tv_nsec != VNOVAL))) error = tmpfs_chtimes(vp, &vap->va_atime, &vap->va_mtime, &vap->va_birthtime, vap->va_vaflags, cred, td); /* Update the node times. We give preference to the error codes * generated by this function rather than the ones that may arise * from tmpfs_update. */ tmpfs_update(vp); MPASS(VOP_ISLOCKED(vp)); return error; }
int tmpfs_access(struct vop_access_args *v) { struct vnode *vp = v->a_vp; accmode_t accmode = v->a_accmode; struct ucred *cred = v->a_cred; int error; struct tmpfs_node *node; MPASS(VOP_ISLOCKED(vp)); node = VP_TO_TMPFS_NODE(vp); switch (vp->v_type) { case VDIR: /* FALLTHROUGH */ case VLNK: /* FALLTHROUGH */ case VREG: if (accmode & VWRITE && vp->v_mount->mnt_flag & MNT_RDONLY) { error = EROFS; goto out; } break; case VBLK: /* FALLTHROUGH */ case VCHR: /* FALLTHROUGH */ case VSOCK: /* FALLTHROUGH */ case VFIFO: break; default: error = EINVAL; goto out; } if (accmode & VWRITE && node->tn_flags & IMMUTABLE) { error = EPERM; goto out; } error = vaccess(vp->v_type, node->tn_mode, node->tn_uid, node->tn_gid, accmode, cred, NULL); out: MPASS(VOP_ISLOCKED(vp)); return error; }
/* * udf_gro_rename_check_permitted: check whether a rename is permitted given * our credentials. */ static int udf_gro_rename_check_permitted(struct mount *mp, kauth_cred_t cred, struct vnode *fdvp, struct vnode *fvp, struct vnode *tdvp, struct vnode *tvp) { struct udf_node *fdir_node = VTOI(fdvp); struct udf_node *tdir_node = VTOI(tdvp); struct udf_node *f_node = VTOI(fvp); struct udf_node *t_node = (tvp? VTOI(tvp): NULL); mode_t fdmode, tdmode; uid_t fduid, tduid, fuid, tuid; gid_t gdummy; (void)mp; KASSERT(mp != NULL); KASSERT(fdvp != NULL); KASSERT(fvp != NULL); KASSERT(tdvp != NULL); KASSERT(fdvp != fvp); KASSERT(fdvp != tvp); KASSERT(tdvp != fvp); KASSERT(tdvp != tvp); KASSERT(fvp != tvp); KASSERT(fdvp->v_type == VDIR); KASSERT(tdvp->v_type == VDIR); KASSERT(fdvp->v_mount == mp); KASSERT(fvp->v_mount == mp); KASSERT(tdvp->v_mount == mp); KASSERT((tvp == NULL) || (tvp->v_mount == mp)); KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE); KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE); KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE); KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE)); DPRINTF(CALL, ("udf_gro_rename_check_permitted called\n")); fdmode = udf_getaccessmode(fdir_node); tdmode = udf_getaccessmode(tdir_node); udf_getownership(fdir_node, &fduid, &gdummy); udf_getownership(tdir_node, &tduid, &gdummy); udf_getownership(f_node, &fuid, &gdummy); tuid = 0; if (t_node) udf_getownership(t_node, &tuid, &gdummy); return genfs_ufslike_rename_check_permitted(cred, fdvp, fdmode, fduid, fvp, fuid, tdvp, tdmode, tduid, tvp, tuid); }
static int tmpfs_remove(struct vop_remove_args *v) { struct vnode *dvp = v->a_dvp; struct vnode *vp = v->a_vp; int error; struct tmpfs_dirent *de; struct tmpfs_mount *tmp; struct tmpfs_node *dnode; struct tmpfs_node *node; MPASS(VOP_ISLOCKED(dvp)); MPASS(VOP_ISLOCKED(vp)); if (vp->v_type == VDIR) { error = EISDIR; goto out; } dnode = VP_TO_TMPFS_DIR(dvp); node = VP_TO_TMPFS_NODE(vp); tmp = VFS_TO_TMPFS(vp->v_mount); de = tmpfs_dir_lookup(dnode, node, v->a_cnp); MPASS(de != NULL); /* Files marked as immutable or append-only cannot be deleted. */ if ((node->tn_flags & (IMMUTABLE | APPEND | NOUNLINK)) || (dnode->tn_flags & APPEND)) { error = EPERM; goto out; } /* Remove the entry from the directory; as it is a file, we do not * have to change the number of hard links of the directory. */ tmpfs_dir_detach(dvp, de); if (v->a_cnp->cn_flags & DOWHITEOUT) tmpfs_dir_whiteout_add(dvp, v->a_cnp); /* Free the directory entry we just deleted. Note that the node * referred by it will not be removed until the vnode is really * reclaimed. */ tmpfs_free_dirent(tmp, de, TRUE); node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED; error = 0; out: return error; }
int adosfs_access(void *v) { struct vop_access_args /* { struct vnode *a_vp; int a_mode; kauth_cred_t a_cred; } */ *sp = v; struct anode *ap; struct vnode *vp = sp->a_vp; int error; #ifdef ADOSFS_DIAGNOSTIC advopprint(sp); #endif ap = VTOA(vp); #ifdef DIAGNOSTIC if (!VOP_ISLOCKED(vp)) { vprint("adosfs_access: not locked", sp->a_vp); panic("adosfs_access: not locked"); } #endif error = adosfs_check_possible(vp, ap, sp->a_mode); if (error) return error; error = adosfs_check_permitted(vp, ap, sp->a_mode, sp->a_cred); #ifdef ADOSFS_DIAGNOSTIC printf(" %d)", error); #endif return(error); }
static int enforce_rlimit_fsize(struct vnode *vp, struct uio *uio, int ioflag) { struct lwp *l = curlwp; off_t testoff; if (uio->uio_rw != UIO_WRITE || vp->v_type != VREG) return 0; KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); if (ioflag & IO_APPEND) testoff = vp->v_size; else testoff = uio->uio_offset; if (testoff + uio->uio_resid > l->l_proc->p_rlimit[RLIMIT_FSIZE].rlim_cur) { mutex_enter(proc_lock); psignal(l->l_proc, SIGXFSZ); mutex_exit(proc_lock); return EFBIG; } return 0; }
/* * genfs_rename_knote: Note events about the various vnodes in a * rename. To be called by gro_rename on success. The only pair of * vnodes that may be identical is {fdvp, tdvp}. deleted_p is true iff * the rename overwrote the last link to tvp. */ void genfs_rename_knote(struct vnode *fdvp, struct vnode *fvp, struct vnode *tdvp, struct vnode *tvp, bool deleted_p) { long fdvp_events, tdvp_events; bool directory_p, reparent_p, replaced_p; KASSERT(fdvp != NULL); KASSERT(fvp != NULL); KASSERT(tdvp != NULL); KASSERT(fdvp != fvp); KASSERT(fdvp != tvp); KASSERT(tdvp != fvp); KASSERT(tdvp != tvp); KASSERT(fvp != tvp); KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE); KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE); KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE); KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE)); directory_p = (fvp->v_type == VDIR); reparent_p = (fdvp != tdvp); replaced_p = (tvp != NULL); KASSERT((tvp == NULL) || (directory_p == (tvp->v_type == VDIR))); KASSERT(!deleted_p || replaced_p); fdvp_events = NOTE_WRITE; if (directory_p && reparent_p) fdvp_events |= NOTE_LINK; VN_KNOTE(fdvp, fdvp_events); VN_KNOTE(fvp, NOTE_RENAME); if (reparent_p) { tdvp_events = NOTE_WRITE; if (!replaced_p) { tdvp_events |= NOTE_EXTEND; if (directory_p) tdvp_events |= NOTE_LINK; } VN_KNOTE(tdvp, tdvp_events); } if (replaced_p) VN_KNOTE(tvp, (deleted_p? NOTE_DELETE : NOTE_LINK)); }
/* * ulfs_gro_directory_empty_p: Return true if the directory vp is * empty. dvp is its parent. * * vp and dvp must be locked and referenced. */ static bool ulfs_gro_directory_empty_p(struct mount *mp, kauth_cred_t cred, struct vnode *vp, struct vnode *dvp) { (void)mp; KASSERT(mp != NULL); KASSERT(vp != NULL); KASSERT(dvp != NULL); KASSERT(vp != dvp); KASSERT(vp->v_mount == mp); KASSERT(dvp->v_mount == mp); KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); return ulfs_dirempty(VTOI(vp), VTOI(dvp)->i_number, cred); }
int VOP_RMDIR(struct vnode *dvp, struct vnode *vp, struct componentname *cnp) { struct vop_rmdir_args a; a.a_desc = VDESC(vop_rmdir); a.a_dvp = dvp; #ifdef VFSDEBUG if ((dvp->v_flag & VLOCKSWORK) && !VOP_ISLOCKED(dvp)) panic("vop_rmdir: dvp"); #endif a.a_vp = vp; #ifdef VFSDEBUG if ((vp->v_flag & VLOCKSWORK) && !VOP_ISLOCKED(vp)) panic("vop_rmdir: vp"); #endif a.a_cnp = cnp; return (VCALL(dvp, VOFFSET(vop_rmdir), &a)); }
/* * Read a symbolic link */ static int pfs_readlink(struct vop_readlink_args *va) { struct vnode *vn = va->a_vp; struct pfs_vdata *pvd = vn->v_data; struct pfs_node *pn = pvd->pvd_pn; struct uio *uio = va->a_uio; struct proc *proc = NULL; struct thread *td = curthread; char buf[PATH_MAX]; struct sbuf sb; int error, locked; PFS_TRACE(("%s", pn->pn_name)); pfs_assert_not_owned(pn); if (vn->v_type != VLNK) PFS_RETURN (EINVAL); KASSERT_PN_IS_LINK(pn); if (pn->pn_fill == NULL) PFS_RETURN (EIO); if (pvd->pvd_pid != NO_PID) { if ((proc = pfind(pvd->pvd_pid)) == NULL) PFS_RETURN (EIO); if (proc->p_flag & P_WEXIT) { PROC_UNLOCK(proc); PFS_RETURN (EIO); } _PHOLD(proc); PROC_UNLOCK(proc); } vhold(vn); locked = VOP_ISLOCKED(vn, td); VOP_UNLOCK(vn, 0, td); /* sbuf_new() can't fail with a static buffer */ sbuf_new(&sb, buf, sizeof buf, 0); error = pn_fill(td, proc, pn, &sb, NULL); if (proc != NULL) PRELE(proc); vn_lock(vn, locked | LK_RETRY, td); vdrop(vn); if (error) { sbuf_delete(&sb); PFS_RETURN (error); } sbuf_finish(&sb); error = uiomove_frombuf(sbuf_data(&sb), sbuf_len(&sb), uio); sbuf_delete(&sb); PFS_RETURN (error); }
/* * genfs_rename_enter: Look up fcnp in fdvp, and store the lookup * results in *fde_ret and the associated vnode in *fvp_ret; fail if * not found. Look up tcnp in tdvp, and store the lookup results in * *tde_ret and the associated vnode in *tvp_ret; store null instead if * not found. Fail if anything has been mounted on any of the nodes * involved. * * fdvp and tdvp must be referenced. * * On entry, nothing is locked. * * On success, everything is locked, and *fvp_ret, and *tvp_ret if * nonnull, are referenced. The only pairs of vnodes that may be * identical are {fdvp, tdvp} and {fvp, tvp}. * * On failure, everything remains as was. * * Locking everything including the source and target nodes is * necessary to make sure that, e.g., link count updates are OK. The * locking order is, in general, ancestor-first, matching the order you * need to use to look up a descendant anyway. */ static int genfs_rename_enter(const struct genfs_rename_ops *ops, struct mount *mp, kauth_cred_t cred, struct vnode *fdvp, struct componentname *fcnp, void *fde_ret, struct vnode **fvp_ret, struct vnode *tdvp, struct componentname *tcnp, void *tde_ret, struct vnode **tvp_ret) { int error; KASSERT(mp != NULL); KASSERT(fdvp != NULL); KASSERT(fcnp != NULL); KASSERT(fvp_ret != NULL); KASSERT(tdvp != NULL); KASSERT(tcnp != NULL); KASSERT(tvp_ret != NULL); KASSERT(fvp_ret != tvp_ret); KASSERT(fdvp->v_type == VDIR); KASSERT(tdvp->v_type == VDIR); KASSERT(fdvp->v_mount == mp); KASSERT(tdvp->v_mount == mp); if (fdvp == tdvp) error = genfs_rename_enter_common(ops, mp, cred, fdvp, fcnp, fde_ret, fvp_ret, tcnp, tde_ret, tvp_ret); else error = genfs_rename_enter_separate(ops, mp, cred, fdvp, fcnp, fde_ret, fvp_ret, tdvp, tcnp, tde_ret, tvp_ret); if (error) return error; KASSERT(*fvp_ret != NULL); KASSERT(VOP_ISLOCKED(*fvp_ret) == LK_EXCLUSIVE); KASSERT((*tvp_ret == NULL) || (VOP_ISLOCKED(*tvp_ret) == LK_EXCLUSIVE)); KASSERT(*fvp_ret != fdvp); KASSERT(*fvp_ret != tdvp); KASSERT(*tvp_ret != fdvp); KASSERT(*tvp_ret != tdvp); return 0; }
static int unionfs_close(void *v) { struct vop_close_args *ap = v; int error; struct unionfs_node *unp; struct unionfs_node_status *unsp; kauth_cred_t cred; struct vnode *ovp; UNIONFS_INTERNAL_DEBUG("unionfs_close: enter\n"); KASSERT(VOP_ISLOCKED(ap->a_vp) == LK_EXCLUSIVE); unp = VTOUNIONFS(ap->a_vp); cred = ap->a_cred; unionfs_get_node_status(unp, &unsp); if (unsp->uns_lower_opencnt <= 0 && unsp->uns_upper_opencnt <= 0) { #ifdef DIAGNOSTIC printf("unionfs_close: warning: open count is 0\n"); #endif if (unp->un_uppervp != NULLVP) ovp = unp->un_uppervp; else ovp = unp->un_lowervp; } else if (unsp->uns_upper_opencnt > 0) ovp = unp->un_uppervp; else ovp = unp->un_lowervp; error = VOP_CLOSE(ovp, ap->a_fflag, cred); if (error != 0) goto unionfs_close_abort; if (ovp == unp->un_uppervp) { unsp->uns_upper_opencnt--; if (unsp->uns_upper_opencnt == 0) { if (unsp->uns_node_flag & UNS_OPENL_4_READDIR) { VOP_CLOSE(unp->un_lowervp, FREAD, cred); unsp->uns_node_flag &= ~UNS_OPENL_4_READDIR; unsp->uns_lower_opencnt--; } } } else unsp->uns_lower_opencnt--; unionfs_close_abort: unionfs_tryrem_node_status(unp, unsp); UNIONFS_INTERNAL_DEBUG("unionfs_close: leave (%d)\n", error); return (error); }
static int tmpfs_fsync(struct vop_fsync_args *v) { struct vnode *vp = v->a_vp; MPASS(VOP_ISLOCKED(vp)); tmpfs_update(vp); return 0; }
/* * ulfs_gro_remove_check_permitted: Check whether a remove is permitted * given our credentials. */ static int ulfs_gro_remove_check_permitted(struct mount *mp, kauth_cred_t cred, struct vnode *dvp, struct vnode *vp) { (void)mp; KASSERT(mp != NULL); KASSERT(dvp != NULL); KASSERT(vp != NULL); KASSERT(dvp != vp); KASSERT(dvp->v_type == VDIR); KASSERT(vp->v_type != VDIR); KASSERT(dvp->v_mount == mp); KASSERT(vp->v_mount == mp); KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); return genfs_ufslike_remove_check_permitted(cred, dvp, VTOI(dvp)->i_mode, VTOI(dvp)->i_uid, vp, VTOI(vp)->i_uid); }
/* * ulfs_rmdired_p: Check whether the directory vp has been rmdired. * * vp must be locked and referenced. */ static bool ulfs_rmdired_p(struct vnode *vp) { KASSERT(vp != NULL); KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); KASSERT(vp->v_type == VDIR); /* XXX Is this correct? */ return (VTOI(vp)->i_size == 0); }
/* * udf_rmdired_p: check whether the directory vp has been rmdired. * * vp must be locked and referenced. */ static bool udf_rmdired_p(struct vnode *vp) { DPRINTF(CALL, ("udf_rmdired_p called\n")); KASSERT(vp != NULL); KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); KASSERT(vp->v_type == VDIR); return (VTOI(vp)->i_flags & IN_DELETED); }
int RUMP_VOP_ISLOCKED(struct vnode *vp) { int error; rump_schedule(); error = VOP_ISLOCKED(vp); rump_unschedule(); return error; }
int ulfs_bufio(enum uio_rw rw, struct vnode *vp, void *buf, size_t len, off_t off, int ioflg, kauth_cred_t cred, size_t *aresid, struct lwp *l) { struct iovec iov; struct uio uio; int error; KASSERT(ISSET(ioflg, IO_NODELOCKED)); KASSERT(VOP_ISLOCKED(vp)); KASSERT(rw != UIO_WRITE || VOP_ISLOCKED(vp) == LK_EXCLUSIVE); iov.iov_base = buf; iov.iov_len = len; uio.uio_iov = &iov; uio.uio_iovcnt = 1; uio.uio_resid = len; uio.uio_offset = off; uio.uio_rw = rw; UIO_SETUP_SYSSPACE(&uio); switch (rw) { case UIO_READ: error = lfs_bufrd(vp, &uio, ioflg, cred); break; case UIO_WRITE: error = lfs_bufwr(vp, &uio, ioflg, cred); break; default: panic("invalid uio rw: %d", (int)rw); } if (aresid) *aresid = uio.uio_resid; else if (uio.uio_resid && error == 0) error = EIO; KASSERT(VOP_ISLOCKED(vp)); KASSERT(rw != UIO_WRITE || VOP_ISLOCKED(vp) == LK_EXCLUSIVE); return error; }