PERFORCE change 120919 for review
Roman Divacky
rdivacky at FreeBSD.org
Mon Jun 4 17:23:59 UTC 2007
http://perforce.freebsd.org/chv.cgi?CH=120919
Change 120919 by rdivacky at rdivacky_witten on 2007/06/04 17:23:48
o Introduce kern_get_at() function instead of duplicating the same
code everywhere
o Reimplement kern_symlink and kern_unlink as wrappers around their *at
counterparts to avoid code duplication
o vrele(dir_vn) in kern_symlink and kern_unlink as necessary
The code upto this commit has bugs :( including panics, deadlocks etc.
Affected files ...
.. //depot/projects/soc2007/rdivacky/linux_at/sys/kern/vfs_syscalls.c#15 edit
Differences ...
==== //depot/projects/soc2007/rdivacky/linux_at/sys/kern/vfs_syscalls.c#15 (text+ko) ====
@@ -85,6 +85,7 @@
static int setfflags(struct thread *td, struct vnode *, int);
static int setutimes(struct thread *td, struct vnode *,
const struct timespec *, int, int);
+static int kern_get_at(struct thread *td, int dirfd, struct vnode **dir_vn);
static int vn_access(struct vnode *vp, int user_flags, struct ucred *cred,
struct thread *td);
static int kern_common_open(struct thread *td, int flags, int mode,
@@ -984,6 +985,26 @@
return kern_common_open(td, flags, mode, &nd);
}
+static int
+kern_get_at(struct thread *td, int dirfd, struct vnode **dir_vn)
+{
+ int error;
+
+ if (dirfd == AT_FDCWD)
+ *dir_vn = NULL;
+ else {
+ error = fgetvp(td, dirfd, dir_vn);
+ if (error)
+ return (error);
+ if ((*dir_vn)->v_type != VDIR) {
+ vrele(*dir_vn);
+ return (ENOTDIR);
+ }
+ }
+
+ return (0);
+}
+
int
kern_openat(struct thread *td, char *path, enum uio_seg pathseg, int flags,
int mode, int dirfd)
@@ -996,22 +1017,14 @@
AUDIT_ARG(mode, mode);
/* XXX: audit dirfd */
- if (dirfd == AT_FDCWD)
- dir_vn = NULL;
- else {
- error = fgetvp(td, dirfd, &dir_vn);
- if (error)
- return (error);
- if (dir_vn->v_type != VDIR) {
- vrele(dir_vn);
- return (ENOTDIR);
- }
- }
+ error = kern_get_at(td, dirfd, &dir_vn);
+ if (error)
+ return (error);
NDINIT_AT(&nd, LOOKUP, FOLLOW | AUDITVNODE1 | MPSAFE, pathseg, path, td, dir_vn);
error = kern_common_open(td, flags, mode, &nd);
- if (dirfd != AT_FDCWD)
+ if (dir_vn)
vrele(dir_vn);
return (error);
}
@@ -1462,47 +1475,25 @@
int error;
struct vnode *pdir_vn, *ldir_vn;
- if (olddirfd == AT_FDCWD)
- pdir_vn = NULL;
- else {
- error = fgetvp(td, olddirfd, &pdir_vn);
- if (error)
- return (error);
- if (pdir_vn->v_type != VDIR) {
- vrele(pdir_vn);
- return (ENOTDIR);
- }
- }
+ error = kern_get_at(td, olddirfd, &pdir_vn);
+ if (error)
+ return (error);
NDINIT_AT(&ndp, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1, segflg, path, td, pdir_vn);
- if (newdirfd == AT_FDCWD)
- ldir_vn = NULL;
- else {
- error = fgetvp(td, newdirfd, &ldir_vn);
- if (error)
- return (error);
- if (ldir_vn->v_type != VDIR) {
- vrele(ldir_vn);
- return (ENOTDIR);
- }
- }
+ error = kern_get_at(td, newdirfd, &ldir_vn);
+ if (error)
+ return (error);
NDINIT_AT(&ndl, CREATE, LOCKPARENT | SAVENAME| MPSAFE | AUDITVNODE1, segflg,
link, td, ldir_vn);
error = kern_common_link(td, &ndp, &ndl);
- if (olddirfd != AT_FDCWD)
+ if (pdir_vn)
vrele(pdir_vn);
- if (newdirfd != AT_FDCWD)
+ if (ldir_vn)
vrele(ldir_vn);
return (error);
-
- NDINIT(&ndp, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1, segflg, path, td);
- NDINIT(&ndl, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE2,
- segflg, link, td);
-
- return kern_common_link(td, &ndp, &ndl);
}
static int
@@ -1587,73 +1578,7 @@
int
kern_symlink(struct thread *td, char *path, char *link, enum uio_seg segflg)
{
- struct mount *mp;
- struct vattr vattr;
- char *syspath;
- int error;
- struct nameidata nd;
- int vfslocked;
-
- if (segflg == UIO_SYSSPACE) {
- syspath = path;
- } else {
- syspath = uma_zalloc(namei_zone, M_WAITOK);
- if ((error = copyinstr(path, syspath, MAXPATHLEN, NULL)) != 0)
- goto out;
- }
- AUDIT_ARG(text, syspath);
-restart:
- bwillwrite();
- NDINIT(&nd, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE1,
- segflg, link, td);
- if ((error = namei(&nd)) != 0)
- goto out;
- vfslocked = NDHASGIANT(&nd);
- if (nd.ni_vp) {
- NDFREE(&nd, NDF_ONLY_PNBUF);
- if (nd.ni_vp == nd.ni_dvp)
- vrele(nd.ni_dvp);
- else
- vput(nd.ni_dvp);
- vrele(nd.ni_vp);
- VFS_UNLOCK_GIANT(vfslocked);
- error = EEXIST;
- goto out;
- }
- if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
- NDFREE(&nd, NDF_ONLY_PNBUF);
- vput(nd.ni_dvp);
- VFS_UNLOCK_GIANT(vfslocked);
- if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
- goto out;
- goto restart;
- }
- VATTR_NULL(&vattr);
- FILEDESC_SLOCK(td->td_proc->p_fd);
- vattr.va_mode = ACCESSPERMS &~ td->td_proc->p_fd->fd_cmask;
- FILEDESC_SUNLOCK(td->td_proc->p_fd);
-#ifdef MAC
- vattr.va_type = VLNK;
- error = mac_check_vnode_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd,
- &vattr);
- if (error)
- goto out2;
-#endif
- VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
- error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, syspath);
- if (error == 0)
- vput(nd.ni_vp);
-#ifdef MAC
-out2:
-#endif
- NDFREE(&nd, NDF_ONLY_PNBUF);
- vput(nd.ni_dvp);
- vn_finished_write(mp);
- VFS_UNLOCK_GIANT(vfslocked);
-out:
- if (segflg != UIO_SYSSPACE)
- uma_zfree(namei_zone, syspath);
- return (error);
+ return kern_symlinkat(td, path, link, segflg, AT_FDCWD);
}
int
@@ -1666,7 +1591,7 @@
int error;
struct nameidata nd;
int vfslocked;
- struct vnode *dir_vn;
+ struct vnode *dir_vn = NULL;
if (segflg == UIO_SYSSPACE) {
syspath = path;
@@ -1677,17 +1602,11 @@
}
AUDIT_ARG(text, syspath);
restart:
- if (dirfd == AT_FDCWD)
- dir_vn = NULL;
- else {
- error = fgetvp(td, dirfd, &dir_vn);
- if (error)
- return (error);
- if (dir_vn->v_type != VDIR) {
- vrele(dir_vn);
- return (ENOTDIR);
- }
- }
+ if (dir_vn)
+ vrele(dir_vn);
+ error = kern_get_at(td, dirfd, &dir_vn);
+ if (error)
+ return (error);
bwillwrite();
NDINIT_AT(&nd, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE1,
segflg, link, td, dir_vn);
@@ -1736,6 +1655,8 @@
vn_finished_write(mp);
VFS_UNLOCK_GIANT(vfslocked);
out:
+ if (dir_vn)
+ vrele(dir_vn);
if (segflg != UIO_SYSSPACE)
uma_zfree(namei_zone, syspath);
return (error);
@@ -1817,94 +1738,32 @@
int
kern_unlink(struct thread *td, char *path, enum uio_seg pathseg)
{
- struct mount *mp;
- struct vnode *vp;
- int error;
- struct nameidata nd;
- int vfslocked;
-
-restart:
- bwillwrite();
- NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF | MPSAFE | AUDITVNODE1,
- pathseg, path, td);
- if ((error = namei(&nd)) != 0)
- return (error == EINVAL ? EPERM : error);
- vfslocked = NDHASGIANT(&nd);
- vp = nd.ni_vp;
- if (vp->v_type == VDIR)
- error = EPERM; /* POSIX */
- else {
- /*
- * The root of a mounted filesystem cannot be deleted.
- *
- * XXX: can this only be a VDIR case?
- */
- if (vp->v_vflag & VV_ROOT)
- error = EBUSY;
- }
- if (error == 0) {
- if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
- NDFREE(&nd, NDF_ONLY_PNBUF);
- vput(nd.ni_dvp);
- if (vp == nd.ni_dvp)
- vrele(vp);
- else
- vput(vp);
- VFS_UNLOCK_GIANT(vfslocked);
- if ((error = vn_start_write(NULL, &mp,
- V_XSLEEP | PCATCH)) != 0)
- return (error);
- goto restart;
- }
-#ifdef MAC
- error = mac_check_vnode_delete(td->td_ucred, nd.ni_dvp, vp,
- &nd.ni_cnd);
- if (error)
- goto out;
-#endif
- VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
- error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd);
-#ifdef MAC
-out:
-#endif
- vn_finished_write(mp);
- }
- NDFREE(&nd, NDF_ONLY_PNBUF);
- vput(nd.ni_dvp);
- if (vp == nd.ni_dvp)
- vrele(vp);
- else
- vput(vp);
- VFS_UNLOCK_GIANT(vfslocked);
- return (error);
+ return kern_unlinkat(td, path, pathseg, AT_FDCWD);
}
int
kern_unlinkat(struct thread *td, char *path, enum uio_seg pathseg, int dirfd)
{
struct mount *mp;
- struct vnode *vp, *dir_vn;
+ struct vnode *vp, *dir_vn = NULL;
int error;
struct nameidata nd;
int vfslocked;
restart:
- if (dirfd == AT_FDCWD)
- dir_vn = NULL;
- else {
- error = fgetvp(td, dirfd, &dir_vn);
- if (error)
- return (error);
- if (dir_vn->v_type != VDIR) {
- vrele(dir_vn);
- return (ENOTDIR);
- }
- }
+ if (dir_vn)
+ vrele(dir_vn);
+ error = kern_get_at(td, dirfd, &dir_vn);
+ if (error)
+ return (error);
bwillwrite();
NDINIT_AT(&nd, DELETE, LOCKPARENT | LOCKLEAF | MPSAFE | AUDITVNODE1,
pathseg, path, td, dir_vn);
- if ((error = namei(&nd)) != 0)
+ if ((error = namei(&nd)) != 0) {
+ if (dir_vn)
+ vrele(dir_vn);
return (error == EINVAL ? EPERM : error);
+ }
vfslocked = NDHASGIANT(&nd);
vp = nd.ni_vp;
if (vp->v_type == VDIR)
@@ -1928,8 +1787,11 @@
vput(vp);
VFS_UNLOCK_GIANT(vfslocked);
if ((error = vn_start_write(NULL, &mp,
- V_XSLEEP | PCATCH)) != 0)
+ V_XSLEEP | PCATCH)) != 0) {
+ if (dir_vn)
+ vrele(dir_vn);
return (error);
+ }
goto restart;
}
#ifdef MAC
@@ -1947,6 +1809,8 @@
}
NDFREE(&nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
+ if (dir_vn)
+ vrele(dir_vn);
if (vp == nd.ni_dvp)
vrele(vp);
else
@@ -2149,23 +2013,15 @@
struct nameidata nd;
struct vnode *dir_vn;
- if (dirfd == AT_FDCWD)
- dir_vn = NULL;
- else {
- error = fgetvp(td, dirfd, &dir_vn);
- if (error)
- return (error);
- if (dir_vn->v_type != VDIR) {
- vrele(dir_vn);
- return (ENOTDIR);
- }
- }
+ error = kern_get_at(td, dirfd, &dir_vn);
+ if (error)
+ return (error);
NDINIT_AT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1,
pathseg, path, td, dir_vn);
error = kern_common_access(td, flags, &nd);
- if (dirfd != AT_FDCWD)
+ if (dir_vn)
vrele(dir_vn);
return (error);
}
@@ -2379,23 +2235,15 @@
struct nameidata nd;
struct vnode *dir_vn;
- if (dirfd == AT_FDCWD)
- dir_vn = NULL;
- else {
- error = fgetvp(td, dirfd, &dir_vn);
- if (error)
- return (error);
- if (dir_vn->v_type != VDIR) {
- vrele(dir_vn);
- return (ENOTDIR);
- }
- }
+ error = kern_get_at(td, dirfd, &dir_vn);
+ if (error)
+ return (error);
NDINIT_AT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | AUDITVNODE1 |
MPSAFE, pathseg, path, td, dir_vn);
error = kern_common_stat(td, sbp, &nd);
- if (dirfd != AT_FDCWD)
+ if (dir_vn)
vrele(dir_vn);
return (error);
}
@@ -2466,23 +2314,15 @@
struct nameidata nd;
struct vnode *dir_vn;
- if (dirfd == AT_FDCWD)
- dir_vn = NULL;
- else {
- error = fgetvp(td, dirfd, &dir_vn);
- if (error)
- return (error);
- if (dir_vn->v_type != VDIR) {
- vrele(dir_vn);
- return (ENOTDIR);
- }
- }
+ error = kern_get_at(td, dirfd, &dir_vn);
+ if (error)
+ return (error);
NDINIT_AT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKSHARED | AUDITVNODE1 |
MPSAFE, pathseg, path, td, dir_vn);
error = kern_common_lstat(td, sbp, &nd);
- if (dirfd != AT_FDCWD)
+ if (dir_vn)
vrele(dir_vn);
return (error);
}
@@ -2677,23 +2517,15 @@
struct nameidata nd;
struct vnode *dir_vn;
- if (dirfd == AT_FDCWD)
- dir_vn = NULL;
- else {
- error = fgetvp(td, dirfd, &dir_vn);
- if (error)
- return (error);
- if (dir_vn->v_type != VDIR) {
- vrele(dir_vn);
- return (ENOTDIR);
- }
- }
+ error = kern_get_at(td, dirfd, &dir_vn);
+ if (error)
+ return (error);
NDINIT_AT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1, pathseg,
path, td, dir_vn);
error = kern_common_readlink(td, buf, bufseg, count, &nd);
- if (dirfd != AT_FDCWD)
+ if (dir_vn)
vrele(dir_vn);
return (error);
}
@@ -2950,22 +2782,14 @@
struct nameidata nd;
struct vnode *dir_vn;
- if (dirfd == AT_FDCWD)
- dir_vn = NULL;
- else {
- error = fgetvp(td, dirfd, &dir_vn);
- if (error)
- return (error);
- if (dir_vn->v_type != VDIR) {
- vrele(dir_vn);
- return (ENOTDIR);
- }
- }
+ error = kern_get_at(td, dirfd, &dir_vn);
+ if (error)
+ return (error);
NDINIT_AT(&nd, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1, pathseg, path, td, dir_vn);
error = kern_common_chmod(td, mode, &nd);
- if (dirfd != AT_FDCWD)
+ if (dir_vn)
vrele(dir_vn);
return (error);
}
@@ -3132,22 +2956,14 @@
struct nameidata nd;
struct vnode *dir_vn;
- if (dirfd == AT_FDCWD)
- dir_vn = NULL;
- else {
- error = fgetvp(td, dirfd, &dir_vn);
- if (error)
- return (error);
- if (dir_vn->v_type != VDIR) {
- vrele(dir_vn);
- return (ENOTDIR);
- }
- }
+ error = kern_get_at(td, dirfd, &dir_vn);
+ if (error)
+ return (error);
NDINIT_AT(&nd, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1, pathseg, path, td, dir_vn);
error = kern_common_chown(td, uid, gid, &nd);
- if (dirfd != AT_FDCWD)
+ if (dir_vn)
vrele(dir_vn);
return (error);
}
@@ -3211,22 +3027,14 @@
struct nameidata nd;
struct vnode *dir_vn;
- if (dirfd == AT_FDCWD)
- dir_vn = NULL;
- else {
- error = fgetvp(td, dirfd, &dir_vn);
- if (error)
- return (error);
- if (dir_vn->v_type != VDIR) {
- vrele(dir_vn);
- return (ENOTDIR);
- }
- }
+ error = kern_get_at(td, dirfd, &dir_vn);
+ if (error)
+ return (error);
NDINIT_AT(&nd, LOOKUP, NOFOLLOW | MPSAFE | AUDITVNODE1, pathseg, path, td, dir_vn);
error = kern_common_chown(td, uid, gid, &nd);
- if (dirfd != AT_FDCWD)
+ if (dir_vn)
vrele(dir_vn);
return (error);
@@ -3978,69 +3786,7 @@
int
kern_rmdir(struct thread *td, char *path, enum uio_seg pathseg)
{
- struct mount *mp;
- struct vnode *vp;
- int error;
- struct nameidata nd;
- int vfslocked;
-
-restart:
- bwillwrite();
- NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF | MPSAFE | AUDITVNODE1,
- pathseg, path, td);
- if ((error = namei(&nd)) != 0)
- return (error);
- vfslocked = NDHASGIANT(&nd);
- vp = nd.ni_vp;
- if (vp->v_type != VDIR) {
- error = ENOTDIR;
- goto out;
- }
- /*
- * No rmdir "." please.
- */
- if (nd.ni_dvp == vp) {
- error = EINVAL;
- goto out;
- }
- /*
- * The root of a mounted filesystem cannot be deleted.
- */
- if (vp->v_vflag & VV_ROOT) {
- error = EBUSY;
- goto out;
- }
-#ifdef MAC
- error = mac_check_vnode_delete(td->td_ucred, nd.ni_dvp, vp,
- &nd.ni_cnd);
- if (error)
- goto out;
-#endif
- if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
- NDFREE(&nd, NDF_ONLY_PNBUF);
- vput(vp);
- if (nd.ni_dvp == vp)
- vrele(nd.ni_dvp);
- else
- vput(nd.ni_dvp);
- VFS_UNLOCK_GIANT(vfslocked);
- if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
- return (error);
- goto restart;
- }
- VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
- VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
- error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
- vn_finished_write(mp);
-out:
- NDFREE(&nd, NDF_ONLY_PNBUF);
- vput(vp);
- if (nd.ni_dvp == vp)
- vrele(nd.ni_dvp);
- else
- vput(nd.ni_dvp);
- VFS_UNLOCK_GIANT(vfslocked);
- return (error);
+ return kern_rmdirat(td, path, pathseg, AT_FDCWD);
}
int
@@ -4053,17 +3799,9 @@
int vfslocked;
restart:
- if (dirfd == AT_FDCWD)
- dir_vn = NULL;
- else {
- error = fgetvp(td, dirfd, &dir_vn);
- if (error)
- return (error);
- if (dir_vn->v_type != VDIR) {
- vrele(dir_vn);
- return (ENOTDIR);
- }
- }
+ error = kern_get_at(td, dirfd, &dir_vn);
+ if (error)
+ return (error);
bwillwrite();
NDINIT_AT(&nd, DELETE, LOCKPARENT | LOCKLEAF | MPSAFE | AUDITVNODE1,
pathseg, path, td, dir_vn);
More information about the p4-projects
mailing list