Index: sys/fs/devfs/devfs_vnops.c =================================================================== --- sys/fs/devfs/devfs_vnops.c +++ sys/fs/devfs/devfs_vnops.c @@ -36,11 +36,6 @@ * $FreeBSD$ */ -/* - * TODO: - * mkdir: want it ? - */ - #include #include #include @@ -1079,6 +1074,47 @@ } static int +devfs_mkdir(struct vop_mkdir_args *ap) +{ + int error; + struct vnode *dvp; + struct devfs_dirent *dd; + struct devfs_dirent *de, *de_covered; + struct devfs_mount *dmp; + + error = priv_check(curthread, PRIV_DEVFS_MKDIR); + if (error) + return(error); + + dvp = ap->a_dvp; + dmp = VFSTODEVFS(dvp->v_mount); + dd = dvp->v_data; + + if (devfs_populate_vp(ap->a_dvp) != 0) + return (ENOENT); + + de_covered = devfs_find(dd, ap->a_cnp->cn_nameptr, + ap->a_cnp->cn_namelen, 0); + if (de_covered != NULL) { + if ((de_covered->de_flags & DE_USER) != 0) { + sx_xunlock(&dmp->dm_lock); + return (EEXIST); + } + KASSERT((de_covered->de_flags & DE_COVERED) == 0, + ("devfs_mkdir: entry %p already covered", de_covered)); + de_covered->de_flags |= DE_COVERED; + } + + de = devfs_vmkdir(dmp, ap->a_cnp->cn_nameptr, + ap->a_cnp->cn_namelen, dd, 0); + + devfs_dir_ref_de(dmp, dd); // XXX: potrzebne? + devfs_rules_apply(dmp, de); + + return (devfs_allocv(de, ap->a_dvp->v_mount, LK_EXCLUSIVE, ap->a_vpp)); +} + +static int devfs_mknod(struct vop_mknod_args *ap) { struct componentname *cnp; @@ -1569,6 +1605,62 @@ } static int +devfs_rmdir(struct vop_rmdir_args *ap) +{ + struct vnode *dvp = ap->a_dvp; + struct vnode *vp = ap->a_vp; + struct devfs_dirent *dd; + struct devfs_dirent *de, *de_dot, *de_dotdot; + struct devfs_mount *dmp = VFSTODEVFS(vp->v_mount); + + ASSERT_VOP_ELOCKED(dvp, "devfs_rmdir"); + ASSERT_VOP_ELOCKED(vp, "devfs_rmdir"); + + sx_xlock(&dmp->dm_lock); + dd = ap->a_dvp->v_data; + de = vp->v_data; + if (de->de_cdp == NULL) { + if ((de->de_flags & DE_DOOMED) != 0 || + de == dmp->dm_rootdir) { + sx_xunlock(&dmp->dm_lock); + return (ENOTEMPTY); + } + + de_dot = TAILQ_FIRST(&de->de_dlist); + KASSERT(de_dot != NULL, ("devfs_rmdir: . missing")); + de_dotdot = TAILQ_NEXT(de_dot, de_list); + KASSERT(de_dotdot != NULL, ("devfs_rmdir: .. missing")); + /* Return if the directory is not empty. */ + if (TAILQ_NEXT(de_dotdot, de_list) != NULL) { + sx_xunlock(&dmp->dm_lock); + return (ENOTEMPTY); + } + + TAILQ_REMOVE(&de->de_dlist, de_dot, de_list); + TAILQ_REMOVE(&de->de_dlist, de_dotdot, de_list); + TAILQ_REMOVE(&dd->de_dlist, de, de_list); + KASSERT(de->de_dirent->d_type != DT_LNK, + ("devfs_rmdir: a link?!")); + /* We need to unlock dvp because devfs_delete() may lock it. */ + VOP_UNLOCK(vp, 0); + if (dvp != vp) + VOP_UNLOCK(dvp, 0); + devfs_delete(dmp, de, 0); + devfs_delete(dmp, de_dot, DEVFS_DEL_NORECURSE); + devfs_delete(dmp, de_dotdot, DEVFS_DEL_NORECURSE); + sx_xunlock(&dmp->dm_lock); + if (dvp != vp) + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + } else { + de->de_flags |= DE_WHITEOUT; + sx_xunlock(&dmp->dm_lock); + } + return (0); +} + + +static int devfs_rioctl(struct vop_ioctl_args *ap) { struct vnode *vp; @@ -1928,6 +2020,7 @@ .vop_getattr = devfs_getattr, .vop_ioctl = devfs_rioctl, .vop_lookup = devfs_lookup, + .vop_mkdir = devfs_mkdir, .vop_mknod = devfs_mknod, .vop_pathconf = devfs_pathconf, .vop_read = devfs_rread, @@ -1936,6 +2029,7 @@ .vop_reclaim = devfs_reclaim, .vop_remove = devfs_remove, .vop_revoke = devfs_revoke, + .vop_rmdir = devfs_rmdir, .vop_setattr = devfs_setattr, #ifdef MAC .vop_setlabel = devfs_setlabel, Index: sys/sys/priv.h =================================================================== --- sys/sys/priv.h +++ sys/sys/priv.h @@ -304,6 +304,7 @@ */ #define PRIV_DEVFS_RULE 370 /* Can manage devfs rules. */ #define PRIV_DEVFS_SYMLINK 371 /* Can create symlinks in devfs. */ +#define PRIV_DEVFS_MKDIR 372 /* Can create directories in devfs. */ /* * Random number generator privileges.