Still awaiting feedback on this diff.
On Fri, Jul 08, 2011 at 03:13:32AM -0700, Matthew Dempsky wrote:
> I missed one flag: AT_REMOVEDIR. This makes unlinkat() behave the
> same as rmdir(), and the diff below changes sys_rmdir() to call
> dounlinkat() using it.
>
> Here's how to read this diff and be convinced it's correct:
>
> 1. First read dounlinkat() by itself, and convince yourself that if
> flag == 0, the behavior is the same as it was already. (The new
> control flow is a little awkward, but the semantics are the
> same.)
>
> 2. Next compare the resulting code with the code in sys_rmdir(), and
> notice that if flag == AT_REMOVEDIR, then they're the same.
>
> ok?
>
>
> Index: sys/fcntl.h
> ===================================================================
> RCS file: /home/mdempsky/anoncvs/cvs/src/sys/sys/fcntl.h,v
> retrieving revision 1.14
> diff -u -p -r1.14 fcntl.h
> --- sys/fcntl.h 8 Jul 2011 04:23:24 -0000 1.14
> +++ sys/fcntl.h 8 Jul 2011 10:05:05 -0000
> @@ -194,6 +194,7 @@ struct flock {
> #define AT_EACCESS 0x01
> #define AT_SYMLINK_NOFOLLOW 0x02
> #define AT_SYMLINK_FOLLOW 0x04
> +#define AT_REMOVEDIR 0x08
> #endif
>
> #ifndef _KERNEL
> Index: kern/vfs_syscalls.c
> ===================================================================
> RCS file: /home/mdempsky/anoncvs/cvs/src/sys/kern/vfs_syscalls.c,v
> retrieving revision 1.170
> diff -u -p -r1.170 vfs_syscalls.c
> --- kern/vfs_syscalls.c 8 Jul 2011 04:23:24 -0000 1.170
> +++ kern/vfs_syscalls.c 8 Jul 2011 10:02:06 -0000
> @@ -1484,9 +1484,8 @@ dounlinkat(struct proc *p, int fd, const
> int error;
> struct nameidata nd;
>
> - /* XXX: Support AT_REMOVEDIR. */
> - if (flag != 0)
> - return (ENOTSUP);
> + if (flag & ~AT_REMOVEDIR)
> + return (EINVAL);
>
> NDINITAT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
> fd, path, p);
> @@ -1494,24 +1493,41 @@ dounlinkat(struct proc *p, int fd, const
> return (error);
> vp = nd.ni_vp;
>
> + if (flag & AT_REMOVEDIR) {
> + if (vp->v_type != VDIR) {
> + error = ENOTDIR;
> + goto out;
> + }
> + /*
> + * No rmdir "." please.
> + */
> + if (nd.ni_dvp == vp) {
> + error = EBUSY;
> + goto out;
> + }
> + }
> +
> /*
> * The root of a mounted filesystem cannot be deleted.
> */
> - if (vp->v_flag & VROOT) {
> + if (vp->v_flag & VROOT)
> + error = EBUSY;
> +out:
> + if (!error) {
> + if (flag & AT_REMOVEDIR) {
> + error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
> + } else {
> + (void)uvm_vnp_uncache(vp);
> + error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
> + }
> + } else {
> VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
> if (nd.ni_dvp == vp)
> vrele(nd.ni_dvp);
> else
> vput(nd.ni_dvp);
> vput(vp);
> - error = EBUSY;
> - goto out;
> }
> -
> - (void)uvm_vnp_uncache(vp);
> -
> - error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
> -out:
> return (error);
> }
>
> @@ -2614,43 +2630,9 @@ sys_rmdir(struct proc *p, void *v, regis
> struct sys_rmdir_args /* {
> syscallarg(const char *) path;
> } */ *uap = v;
> - struct vnode *vp;
> - int error;
> - struct nameidata nd;
>
> - NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
> - SCARG(uap, path), p);
> - if ((error = namei(&nd)) != 0)
> - return (error);
> - vp = nd.ni_vp;
> - if (vp->v_type != VDIR) {
> - error = ENOTDIR;
> - goto out;
> - }
> - /*
> - * No rmdir "." please.
> - */
> - if (nd.ni_dvp == vp) {
> - error = EBUSY;
> - goto out;
> - }
> - /*
> - * The root of a mounted filesystem cannot be deleted.
> - */
> - if (vp->v_flag & VROOT)
> - error = EBUSY;
> -out:
> - if (!error) {
> - error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
> - } else {
> - VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
> - if (nd.ni_dvp == vp)
> - vrele(nd.ni_dvp);
> - else
> - vput(nd.ni_dvp);
> - vput(vp);
> - }
> - return (error);
> + return (dounlinkat(p, AT_FDCWD, SCARG(uap, path), AT_REMOVEDIR,
> + retval));
> }
>
> /*