1185029Spjd/*-
2185029Spjd * Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3185029Spjd * All rights reserved.
4185029Spjd *
5185029Spjd * Redistribution and use in source and binary forms, with or without
6185029Spjd * modification, are permitted provided that the following conditions
7185029Spjd * are met:
8185029Spjd * 1. Redistributions of source code must retain the above copyright
9185029Spjd *    notice, this list of conditions and the following disclaimer.
10185029Spjd * 2. Redistributions in binary form must reproduce the above copyright
11185029Spjd *    notice, this list of conditions and the following disclaimer in the
12185029Spjd *    documentation and/or other materials provided with the distribution.
13185029Spjd *
14185029Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15185029Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16185029Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17185029Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18185029Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19185029Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20185029Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21185029Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22185029Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23185029Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24185029Spjd * SUCH DAMAGE.
25185029Spjd */
26185029Spjd
27185029Spjd#include <sys/cdefs.h>
28185029Spjd__FBSDID("$FreeBSD$");
29185029Spjd
30185029Spjd#include <sys/param.h>
31185029Spjd#include <sys/kernel.h>
32185029Spjd#include <sys/systm.h>
33185029Spjd#include <sys/pathname.h>
34185029Spjd#include <sys/vfs.h>
35185029Spjd#include <sys/vnode.h>
36185029Spjd
37185029Spjdint
38185029Spjdlookupname(char *dirname, enum uio_seg seg, enum symfollow follow,
39185029Spjd    vnode_t **dirvpp, vnode_t **compvpp)
40185029Spjd{
41185029Spjd
42185029Spjd	return (lookupnameat(dirname, seg, follow, dirvpp, compvpp, NULL));
43185029Spjd}
44185029Spjd
45185029Spjdint
46185029Spjdlookupnameat(char *dirname, enum uio_seg seg, enum symfollow follow,
47185029Spjd    vnode_t **dirvpp, vnode_t **compvpp, vnode_t *startvp)
48185029Spjd{
49185029Spjd	struct nameidata nd;
50185029Spjd	int error, ltype;
51185029Spjd
52185029Spjd	ASSERT(dirvpp == NULL);
53185029Spjd
54185029Spjd	vref(startvp);
55185029Spjd	ltype = VOP_ISLOCKED(startvp);
56185029Spjd	VOP_UNLOCK(startvp, 0);
57241896Skib	NDINIT_ATVP(&nd, LOOKUP, LOCKLEAF | follow, seg, dirname,
58185029Spjd	    startvp, curthread);
59185029Spjd	error = namei(&nd);
60185029Spjd	*compvpp = nd.ni_vp;
61185029Spjd	NDFREE(&nd, NDF_ONLY_PNBUF);
62185029Spjd	vn_lock(startvp, ltype | LK_RETRY);
63185029Spjd	return (error);
64185029Spjd}
65185029Spjd
66185029Spjdint
67185029Spjdtraverse(vnode_t **cvpp, int lktype)
68185029Spjd{
69185029Spjd	vnode_t *cvp;
70185029Spjd	vnode_t *tvp;
71185029Spjd	vfs_t *vfsp;
72185029Spjd	int error;
73185029Spjd
74185029Spjd	cvp = *cvpp;
75185029Spjd	tvp = NULL;
76185029Spjd
77185029Spjd	/*
78185029Spjd	 * If this vnode is mounted on, then we transparently indirect
79185029Spjd	 * to the vnode which is the root of the mounted file system.
80185029Spjd	 * Before we do this we must check that an unmount is not in
81185029Spjd	 * progress on this vnode.
82185029Spjd	 */
83185029Spjd
84185029Spjd	for (;;) {
85185029Spjd		/*
86185029Spjd		 * Reached the end of the mount chain?
87185029Spjd		 */
88185029Spjd		vfsp = vn_mountedvfs(cvp);
89185029Spjd		if (vfsp == NULL)
90185029Spjd			break;
91242569Savg		error = vfs_busy(vfsp, 0);
92185029Spjd		/*
93185029Spjd		 * tvp is NULL for *cvpp vnode, which we can't unlock.
94185029Spjd		 */
95185029Spjd		if (tvp != NULL)
96185029Spjd			vput(cvp);
97185029Spjd		else
98185029Spjd			vrele(cvp);
99242569Savg		if (error)
100242569Savg			return (error);
101185029Spjd
102185029Spjd		/*
103185029Spjd		 * The read lock must be held across the call to VFS_ROOT() to
104185029Spjd		 * prevent a concurrent unmount from destroying the vfs.
105185029Spjd		 */
106191990Sattilio		error = VFS_ROOT(vfsp, lktype, &tvp);
107242569Savg		vfs_unbusy(vfsp);
108185029Spjd		if (error != 0)
109185029Spjd			return (error);
110185029Spjd		cvp = tvp;
111185029Spjd	}
112185029Spjd
113185029Spjd	*cvpp = cvp;
114185029Spjd	return (0);
115185029Spjd}
116