diff options
author | Jerry Gilliam <Jerry.Gilliam@Sun.COM> | 2008-10-31 14:32:38 -0700 |
---|---|---|
committer | Jerry Gilliam <Jerry.Gilliam@Sun.COM> | 2008-10-31 14:32:38 -0700 |
commit | 74bb9a80871576998889a2cdbffe159e60b4167f (patch) | |
tree | fd90805a295eec60693c8d5184c8dc4b78720169 /usr/src/uts/common/fs/dev/sdev_subr.c | |
parent | 49fbdd30212f016ddd49c4b5c997b0b827ff0962 (diff) | |
download | illumos-gate-74bb9a80871576998889a2cdbffe159e60b4167f.tar.gz |
6751491 devfsadm check causes panic on clustered systems
Diffstat (limited to 'usr/src/uts/common/fs/dev/sdev_subr.c')
-rw-r--r-- | usr/src/uts/common/fs/dev/sdev_subr.c | 75 |
1 files changed, 70 insertions, 5 deletions
diff --git a/usr/src/uts/common/fs/dev/sdev_subr.c b/usr/src/uts/common/fs/dev/sdev_subr.c index 7a926cab67..127329c8d4 100644 --- a/usr/src/uts/common/fs/dev/sdev_subr.c +++ b/usr/src/uts/common/fs/dev/sdev_subr.c @@ -2971,7 +2971,6 @@ done: return (error); } - static int sdev_modctl_lookup(const char *path, vnode_t **r_vp) { @@ -2983,6 +2982,8 @@ sdev_modctl_lookup(const char *path, vnode_t **r_vp) int error; int persisted = 0; + ASSERT(INGLOBALZONE(curproc)); + if (error = pn_get((char *)path, UIO_SYSSPACE, &pn)) return (error); nm = kmem_alloc(MAXNAMELEN, KM_SLEEP); @@ -2991,22 +2992,86 @@ sdev_modctl_lookup(const char *path, vnode_t **r_vp) VN_HOLD(vp); while (pn_pathleft(&pn)) { - ASSERT(vp->v_type == VDIR); + ASSERT(vp->v_type == VDIR || vp->v_type == VLNK); (void) pn_getcomponent(&pn, nm); + + /* + * Deal with the .. special case where we may be + * traversing up across a mount point, to the + * root of this filesystem or global root. + */ + if (nm[0] == '.' && nm[1] == '.' && nm[2] == 0) { +checkforroot: + if (VN_CMP(vp, rootdir)) { + nm[1] = 0; + } else if (vp->v_flag & VROOT) { + vfs_t *vfsp; + cvp = vp; + vfsp = cvp->v_vfsp; + vfs_rlock_wait(vfsp); + vp = cvp->v_vfsp->vfs_vnodecovered; + if (vp == NULL || + (cvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) { + vfs_unlock(vfsp); + VN_RELE(cvp); + error = EIO; + break; + } + VN_HOLD(vp); + vfs_unlock(vfsp); + VN_RELE(cvp); + cvp = NULL; + goto checkforroot; + } + } + error = VOP_LOOKUP(vp, nm, &cvp, NULL, 0, NULL, kcred, NULL, NULL, NULL); - VN_RELE(vp); - - if (error) + if (error) { + VN_RELE(vp); break; + } /* traverse mount points encountered on our journey */ if (vn_ismntpt(cvp) && (error = traverse(&cvp)) != 0) { + VN_RELE(vp); VN_RELE(cvp); break; } /* + * symbolic link, can be either relative and absolute + */ + if ((cvp->v_type == VLNK) && pn_pathleft(&pn)) { + struct pathname linkpath; + pn_alloc(&linkpath); + if (error = pn_getsymlink(cvp, &linkpath, kcred)) { + pn_free(&linkpath); + break; + } + if (pn_pathleft(&linkpath) == 0) + (void) pn_set(&linkpath, "."); + error = pn_insert(&pn, &linkpath, strlen(nm)); + pn_free(&linkpath); + if (pn.pn_pathlen == 0) { + VN_RELE(vp); + return (ENOENT); + } + if (pn.pn_path[0] == '/') { + pn_skipslash(&pn); + VN_RELE(vp); + VN_RELE(cvp); + vp = rootdir; + VN_HOLD(vp); + } else { + VN_RELE(cvp); + } + continue; + } + + VN_RELE(vp); + + /* * Direct the operation to the persisting filesystem * underlying /dev. Bail if we encounter a * non-persistent dev entity here. |