From: Thomas Veerman Date: Tue, 20 Nov 2012 13:14:31 +0000 (+0000) Subject: VFS: change 'last_dir' to match locking assumption X-Git-Tag: v3.2.1~189 X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/man.dnssec-checkds.html?a=commitdiff_plain;h=de83b2a9d9cb8f97d731db4814869534755dd016;p=minix.git VFS: change 'last_dir' to match locking assumption new_node makes the assumption that when it does last_dir on a path, a successive advance would not yield a lock on a vmnt, because last_dir already locked the vmnt. This is true except when last_dir resolves to a directory on the parent vmnt of the file that was the result of advance. For example, # cd / # echo foo > home where home is on a different (sub) partition than / is (default install). last_dir would resolve to / and advance would resolve to /home. With this change, last_dir resolves to the root node on the /home partition, making the assumption valid again. --- diff --git a/servers/vfs/open.c b/servers/vfs/open.c index 0a0edf80f..bd945371c 100644 --- a/servers/vfs/open.c +++ b/servers/vfs/open.c @@ -444,9 +444,9 @@ static struct vnode *new_node(struct lookup *resolve, int oflags, mode_t bits) else err_code = r; + unlock_vmnt(dir_vmp); unlock_vnode(dirp); unlock_vnode(vp); - unlock_vmnt(dir_vmp); put_vnode(dirp); return(NULL); } diff --git a/servers/vfs/path.c b/servers/vfs/path.c index c19f1e135..63de98f80 100644 --- a/servers/vfs/path.c +++ b/servers/vfs/path.c @@ -264,7 +264,9 @@ struct fproc *rfp; symlink.l_vmnt_lock = VMNT_READ; sym_vp = advance(res_vp, &symlink, rfp); - if (sym_vp != NULL && S_ISLNK(sym_vp->v_mode)) { + if (sym_vp == NULL) break; + + if (S_ISLNK(sym_vp->v_mode)) { /* Last component is a symlink, but if we've been asked to not * resolve it, return now. */ @@ -310,6 +312,41 @@ struct fproc *rfp; continue; } + } else { + symloop = 0; /* Not a symlink, so restart counting */ + + /* If we're crossing a mount point, return root node of mount + * point on which the file resides. That's the 'real' last + * dir that holds the file we're looking for. + */ + if (sym_vp->v_fs_e != res_vp->v_fs_e) { + assert(sym_vmp != NULL); + + /* Unlock final file, it might have wrong lock types */ + unlock_vnode(sym_vp); + unlock_vmnt(sym_vmp); + put_vnode(sym_vp); + sym_vp = NULL; + + /* Also unlock and release erroneous result */ + unlock_vnode(*resolve->l_vnode); + unlock_vmnt(*resolve->l_vmp); + put_vnode(res_vp); + + /* Relock vmnt and vnode with correct lock types */ + lock_vmnt(sym_vmp, resolve->l_vmnt_lock); + lock_vnode(sym_vmp->m_root_node, resolve->l_vnode_lock); + res_vp = sym_vmp->m_root_node; + dup_vnode(res_vp); + *resolve->l_vnode = res_vp; + *resolve->l_vmp = sym_vmp; + + /* We've effectively resolved the final component, so + * change it to current directory to prevent future + * 'advances' of returning erroneous results. + */ + strlcpy(dir_entry, ".", NAME_MAX+1); + } } break; } while (symloop < SYMLOOP_MAX);