vfs_cwd.c revision 1.4.62.2 1 1.4.62.2 ad /* $NetBSD: vfs_cwd.c,v 1.4.62.2 2020/01/25 18:42:24 ad Exp $ */
2 1.1 pooka
3 1.1 pooka /*-
4 1.4.62.1 ad * Copyright (c) 2008, 2020 The NetBSD Foundation, Inc.
5 1.1 pooka * All rights reserved.
6 1.1 pooka *
7 1.1 pooka * Redistribution and use in source and binary forms, with or without
8 1.1 pooka * modification, are permitted provided that the following conditions
9 1.1 pooka * are met:
10 1.1 pooka * 1. Redistributions of source code must retain the above copyright
11 1.1 pooka * notice, this list of conditions and the following disclaimer.
12 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 pooka * notice, this list of conditions and the following disclaimer in the
14 1.1 pooka * documentation and/or other materials provided with the distribution.
15 1.1 pooka *
16 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 1.1 pooka * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 1.1 pooka * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 1.1 pooka * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 1.1 pooka * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 1.1 pooka * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 1.1 pooka * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 1.1 pooka * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 1.1 pooka * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 1.1 pooka * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 1.1 pooka * POSSIBILITY OF SUCH DAMAGE.
27 1.1 pooka */
28 1.1 pooka
29 1.1 pooka /*
30 1.1 pooka * Current working directory.
31 1.1 pooka */
32 1.1 pooka
33 1.1 pooka #include <sys/cdefs.h>
34 1.4.62.2 ad __KERNEL_RCSID(0, "$NetBSD: vfs_cwd.c,v 1.4.62.2 2020/01/25 18:42:24 ad Exp $");
35 1.1 pooka
36 1.1 pooka #include <sys/param.h>
37 1.1 pooka #include <sys/atomic.h>
38 1.1 pooka #include <sys/filedesc.h>
39 1.1 pooka #include <sys/proc.h>
40 1.1 pooka #include <sys/vnode.h>
41 1.4.62.1 ad #include <sys/xcall.h>
42 1.1 pooka
43 1.1 pooka static int cwdi_ctor(void *, void *, int);
44 1.1 pooka static void cwdi_dtor(void *, void *);
45 1.1 pooka
46 1.1 pooka static pool_cache_t cwdi_cache;
47 1.1 pooka
48 1.1 pooka void
49 1.1 pooka cwd_sys_init(void)
50 1.1 pooka {
51 1.1 pooka
52 1.1 pooka cwdi_cache = pool_cache_init(sizeof(struct cwdinfo), coherency_unit,
53 1.1 pooka 0, 0, "cwdi", NULL, IPL_NONE, cwdi_ctor, cwdi_dtor, NULL);
54 1.1 pooka KASSERT(cwdi_cache != NULL);
55 1.1 pooka }
56 1.1 pooka
57 1.1 pooka /*
58 1.1 pooka * Create an initial cwdinfo structure, using the same current and root
59 1.1 pooka * directories as curproc.
60 1.1 pooka */
61 1.1 pooka struct cwdinfo *
62 1.1 pooka cwdinit(void)
63 1.1 pooka {
64 1.1 pooka struct cwdinfo *cwdi;
65 1.1 pooka struct cwdinfo *copy;
66 1.1 pooka
67 1.1 pooka cwdi = pool_cache_get(cwdi_cache, PR_WAITOK);
68 1.1 pooka
69 1.4.62.1 ad copy = cwdenter(RW_READER);
70 1.1 pooka cwdi->cwdi_cdir = copy->cwdi_cdir;
71 1.1 pooka if (cwdi->cwdi_cdir)
72 1.3 pooka vref(cwdi->cwdi_cdir);
73 1.1 pooka cwdi->cwdi_rdir = copy->cwdi_rdir;
74 1.1 pooka if (cwdi->cwdi_rdir)
75 1.3 pooka vref(cwdi->cwdi_rdir);
76 1.1 pooka cwdi->cwdi_edir = copy->cwdi_edir;
77 1.1 pooka if (cwdi->cwdi_edir)
78 1.3 pooka vref(cwdi->cwdi_edir);
79 1.2 yamt cwdi->cwdi_cmask = copy->cwdi_cmask;
80 1.1 pooka cwdi->cwdi_refcnt = 1;
81 1.4.62.1 ad cwdexit(copy);
82 1.1 pooka
83 1.1 pooka return (cwdi);
84 1.1 pooka }
85 1.1 pooka
86 1.1 pooka static int
87 1.1 pooka cwdi_ctor(void *arg, void *obj, int flags)
88 1.1 pooka {
89 1.1 pooka struct cwdinfo *cwdi = obj;
90 1.1 pooka
91 1.4.62.1 ad mutex_init(&cwdi->cwdi_lock, MUTEX_DEFAULT, IPL_NONE);
92 1.1 pooka
93 1.1 pooka return 0;
94 1.1 pooka }
95 1.1 pooka
96 1.1 pooka static void
97 1.1 pooka cwdi_dtor(void *arg, void *obj)
98 1.1 pooka {
99 1.1 pooka struct cwdinfo *cwdi = obj;
100 1.1 pooka
101 1.4.62.1 ad mutex_destroy(&cwdi->cwdi_lock);
102 1.1 pooka }
103 1.1 pooka
104 1.1 pooka /*
105 1.1 pooka * Make p2 share p1's cwdinfo.
106 1.1 pooka */
107 1.1 pooka void
108 1.1 pooka cwdshare(struct proc *p2)
109 1.1 pooka {
110 1.1 pooka struct cwdinfo *cwdi;
111 1.1 pooka
112 1.1 pooka cwdi = curproc->p_cwdi;
113 1.1 pooka
114 1.1 pooka atomic_inc_uint(&cwdi->cwdi_refcnt);
115 1.1 pooka p2->p_cwdi = cwdi;
116 1.1 pooka }
117 1.1 pooka
118 1.1 pooka /*
119 1.1 pooka * Make sure proc has only one reference to its cwdi, creating
120 1.1 pooka * a new one if necessary.
121 1.1 pooka */
122 1.1 pooka void
123 1.1 pooka cwdunshare(struct proc *p)
124 1.1 pooka {
125 1.1 pooka struct cwdinfo *cwdi = p->p_cwdi;
126 1.1 pooka
127 1.1 pooka if (cwdi->cwdi_refcnt > 1) {
128 1.1 pooka cwdi = cwdinit();
129 1.1 pooka cwdfree(p->p_cwdi);
130 1.1 pooka p->p_cwdi = cwdi;
131 1.1 pooka }
132 1.1 pooka }
133 1.1 pooka
134 1.1 pooka /*
135 1.1 pooka * Release a cwdinfo structure.
136 1.1 pooka */
137 1.1 pooka void
138 1.1 pooka cwdfree(struct cwdinfo *cwdi)
139 1.1 pooka {
140 1.1 pooka
141 1.1 pooka if (atomic_dec_uint_nv(&cwdi->cwdi_refcnt) > 0)
142 1.1 pooka return;
143 1.1 pooka
144 1.1 pooka vrele(cwdi->cwdi_cdir);
145 1.1 pooka if (cwdi->cwdi_rdir)
146 1.1 pooka vrele(cwdi->cwdi_rdir);
147 1.1 pooka if (cwdi->cwdi_edir)
148 1.1 pooka vrele(cwdi->cwdi_edir);
149 1.1 pooka pool_cache_put(cwdi_cache, cwdi);
150 1.1 pooka }
151 1.4 pooka
152 1.4 pooka void
153 1.4 pooka cwdexec(struct proc *p)
154 1.4 pooka {
155 1.4 pooka
156 1.4 pooka cwdunshare(p);
157 1.4 pooka
158 1.4 pooka if (p->p_cwdi->cwdi_edir) {
159 1.4 pooka vrele(p->p_cwdi->cwdi_edir);
160 1.4 pooka }
161 1.4 pooka }
162 1.4.62.1 ad
163 1.4.62.1 ad /*
164 1.4.62.1 ad * Used when curlwp wants to use or update its cwdinfo, and needs to prevent
165 1.4.62.1 ad * concurrent changes.
166 1.4.62.1 ad *
167 1.4.62.1 ad * "op" is either RW_READER or RW_WRITER indicating the kind of lock
168 1.4.62.1 ad * required. If a read lock on the cwdinfo is requested, then curlwp must
169 1.4.62.1 ad * not block while holding the lock, or the cwdinfo could become stale.
170 1.4.62.1 ad * It's okay to block while holding a write lock.
171 1.4.62.1 ad */
172 1.4.62.1 ad struct cwdinfo *
173 1.4.62.1 ad cwdenter(krw_t op)
174 1.4.62.1 ad {
175 1.4.62.1 ad struct cwdinfo *cwdi = curproc->p_cwdi;
176 1.4.62.1 ad
177 1.4.62.1 ad if (__predict_true(op == RW_READER)) {
178 1.4.62.1 ad /*
179 1.4.62.1 ad * Disable preemption to hold off the writer side's xcall,
180 1.4.62.1 ad * then observe the lock. If it's already taken, we need to
181 1.4.62.1 ad * join in the melee. Otherwise we're good to go; keeping
182 1.4.62.1 ad * the xcall at bay with kpreempt_disable() will prevent any
183 1.4.62.1 ad * changes while the caller is pondering the cwdinfo.
184 1.4.62.1 ad */
185 1.4.62.1 ad kpreempt_disable();
186 1.4.62.2 ad if (__predict_true(mutex_owner(&cwdi->cwdi_lock) == NULL)) {
187 1.4.62.2 ad membar_consumer();
188 1.4.62.1 ad return cwdi;
189 1.4.62.2 ad }
190 1.4.62.1 ad kpreempt_enable();
191 1.4.62.1 ad mutex_enter(&cwdi->cwdi_lock);
192 1.4.62.1 ad } else {
193 1.4.62.1 ad /*
194 1.4.62.1 ad * About to make changes. If there's more than one
195 1.4.62.1 ad * reference on the cwdinfo, or curproc has more than one
196 1.4.62.1 ad * LWP, then LWPs other than curlwp can also see the
197 1.4.62.1 ad * cwdinfo. Run a cross call to get all LWPs out of the
198 1.4.62.1 ad * read section. This also acts as a global memory barrier,
199 1.4.62.1 ad * meaning we don't need to do anything special with on
200 1.4.62.1 ad * the reader side.
201 1.4.62.1 ad */
202 1.4.62.1 ad mutex_enter(&cwdi->cwdi_lock);
203 1.4.62.1 ad if (cwdi->cwdi_refcnt + curproc->p_nlwps > 2)
204 1.4.62.1 ad xc_barrier(0);
205 1.4.62.1 ad }
206 1.4.62.1 ad return cwdi;
207 1.4.62.1 ad }
208 1.4.62.1 ad
209 1.4.62.1 ad /*
210 1.4.62.1 ad * Release a lock previously taken with cwdenter().
211 1.4.62.1 ad */
212 1.4.62.1 ad void
213 1.4.62.1 ad cwdexit(struct cwdinfo *cwdi)
214 1.4.62.1 ad {
215 1.4.62.1 ad struct lwp *l = curlwp;
216 1.4.62.1 ad
217 1.4.62.1 ad KASSERT(cwdi == l->l_proc->p_cwdi);
218 1.4.62.1 ad
219 1.4.62.1 ad if (__predict_true(mutex_owner(&cwdi->cwdi_lock) != l))
220 1.4.62.1 ad kpreempt_enable();
221 1.4.62.1 ad else
222 1.4.62.1 ad mutex_exit(&cwdi->cwdi_lock);
223 1.4.62.1 ad }
224 1.4.62.1 ad
225 1.4.62.1 ad /*
226 1.4.62.1 ad * Called when there is a need to inspect some other process' cwdinfo. Used
227 1.4.62.1 ad * by procfs and sysctl. This gets you a read lock; the cwdinfo must NOT be
228 1.4.62.1 ad * changed.
229 1.4.62.1 ad */
230 1.4.62.1 ad const struct cwdinfo *
231 1.4.62.1 ad cwdlock(struct proc *p)
232 1.4.62.1 ad {
233 1.4.62.1 ad struct cwdinfo *cwdi = p->p_cwdi;
234 1.4.62.1 ad
235 1.4.62.1 ad mutex_enter(&cwdi->cwdi_lock);
236 1.4.62.1 ad return cwdi;
237 1.4.62.1 ad }
238 1.4.62.1 ad
239 1.4.62.1 ad /*
240 1.4.62.1 ad * Release a lock acquired with cwdlock().
241 1.4.62.1 ad */
242 1.4.62.1 ad void
243 1.4.62.1 ad cwdunlock(struct proc *p)
244 1.4.62.1 ad {
245 1.4.62.1 ad struct cwdinfo *cwdi = p->p_cwdi;
246 1.4.62.1 ad
247 1.4.62.1 ad mutex_exit(&cwdi->cwdi_lock);
248 1.4.62.1 ad }
249 1.4.62.1 ad
250 1.4.62.1 ad /*
251 1.4.62.1 ad * Get a reference to the current working directory and return it.
252 1.4.62.1 ad */
253 1.4.62.1 ad struct vnode *
254 1.4.62.1 ad cwdcdir(void)
255 1.4.62.1 ad {
256 1.4.62.1 ad struct cwdinfo *cwdi;
257 1.4.62.1 ad struct vnode *vp;
258 1.4.62.1 ad
259 1.4.62.1 ad cwdi = cwdenter(RW_READER);
260 1.4.62.1 ad if ((vp = cwdi->cwdi_cdir) != NULL)
261 1.4.62.1 ad vref(vp);
262 1.4.62.1 ad cwdexit(cwdi);
263 1.4.62.1 ad return vp;
264 1.4.62.1 ad }
265 1.4.62.1 ad
266 1.4.62.1 ad /*
267 1.4.62.1 ad * Get a reference to the root directory and return it.
268 1.4.62.1 ad */
269 1.4.62.1 ad struct vnode *
270 1.4.62.1 ad cwdrdir(void)
271 1.4.62.1 ad {
272 1.4.62.1 ad struct cwdinfo *cwdi;
273 1.4.62.1 ad struct vnode *vp;
274 1.4.62.1 ad
275 1.4.62.1 ad cwdi = cwdenter(RW_READER);
276 1.4.62.1 ad if ((vp = cwdi->cwdi_rdir) != NULL)
277 1.4.62.1 ad vref(vp);
278 1.4.62.1 ad cwdexit(cwdi);
279 1.4.62.1 ad return vp;
280 1.4.62.1 ad }
281