1 /* $NetBSD: puffs_subr.c,v 1.9 2006/11/18 08:18:24 pooka Exp $ */
2
3 /*
4 * Copyright (c) 2005, 2006 Antti Kantee. All Rights Reserved.
5 *
6 * Development of this software was supported by the
7 * Google Summer of Code program and the Ulla Tuominen Foundation.
8 * The Google SoC project was mentored by Bill Studenmund.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. The name of the company nor the name of the author may be used to
19 * endorse or promote products derived from this software without specific
20 * prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
23 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: puffs_subr.c,v 1.9 2006/11/18 08:18:24 pooka Exp $");
37
38 #include <sys/param.h>
39 #include <sys/conf.h>
40 #include <sys/malloc.h>
41 #include <sys/mount.h>
42 #include <sys/socketvar.h>
43 #include <sys/vnode.h>
44 #include <sys/kauth.h>
45 #include <sys/namei.h>
46
47 #include <fs/puffs/puffs_msgif.h>
48 #include <fs/puffs/puffs_sys.h>
49
50 #include <miscfs/genfs/genfs_node.h>
51 #include <miscfs/specfs/specdev.h>
52
53 POOL_INIT(puffs_pnpool, sizeof(struct puffs_node), 0, 0, 0, "puffspnpl",
54 &pool_allocator_nointr);
55
56
57 static void puffs_gop_size(struct vnode *, off_t, off_t *, int);
58 static void puffs_gop_markupdate(struct vnode *, int);
59
60 static const struct genfs_ops puffs_genfsops = {
61 .gop_size = puffs_gop_size,
62 .gop_write = genfs_gop_write,
63 .gop_markupdate = puffs_gop_markupdate,
64 #if 0
65 .gop_alloc, should ask userspace
66 #endif
67 };
68
69 /*
70 * Grab a vnode, intialize all the puffs-dependant stuff.
71 */
72 int
73 puffs_getvnode(struct mount *mp, void *cookie, enum vtype type,
74 voff_t vsize, dev_t rdev, struct vnode **vpp)
75 {
76 struct puffs_mount *pmp;
77 struct vnode *vp, *nvp;
78 struct puffs_node *pnode;
79 int error;
80
81 pmp = MPTOPUFFSMP(mp);
82
83 /*
84 * XXX: there is a deadlock condition between vfs_busy() and
85 * vnode locks. For an unmounting file system the mountpoint
86 * is frozen, but in unmount(FORCE) vflush() wants to access all
87 * of the vnodes. If we are here waiting for the mountpoint
88 * lock while holding on to a vnode lock, well, we ain't
89 * just pining for the fjords anymore. If we release the
90 * vnode lock, we will be in the situation "mount point
91 * is dying" and panic() will ensue in insmntque. So as a
92 * temporary workaround, get a vnode without putting it on
93 * the mount point list, check if mount point is still alive
94 * and kicking and only then add the vnode to the list.
95 */
96 error = getnewvnode(VT_PUFFS, NULL, puffs_vnodeop_p, &vp);
97 if (error)
98 return error;
99 vp->v_vnlock = NULL;
100 vp->v_type = type;
101
102 /*
103 * Check what mount point isn't going away. This will work
104 * until we decide to remove biglock or make the kernel
105 * preemptive. But hopefully the real problem will be fixed
106 * by then.
107 *
108 * XXX: yes, should call vfs_busy(), but thar be rabbits with
109 * vicious streaks a mile wide ...
110 */
111 if (mp->mnt_iflag & IMNT_UNMOUNT) {
112 DPRINTF(("puffs_getvnode: mp %p unmount, unable to create "
113 "vnode for cookie %p\n", mp, cookie));
114 ungetnewvnode(vp);
115 return ENXIO;
116 }
117
118 /* So it's not dead yet.. good.. inform new vnode of its master */
119 simple_lock(&mntvnode_slock);
120 if (TAILQ_EMPTY(&mp->mnt_vnodelist))
121 TAILQ_INSERT_HEAD(&mp->mnt_vnodelist, vp, v_mntvnodes);
122 else
123 TAILQ_INSERT_TAIL(&mp->mnt_vnodelist, vp, v_mntvnodes);
124 simple_unlock(&mntvnode_slock);
125 vp->v_mount = mp;
126
127 /*
128 * clerical tasks & footwork
129 */
130
131 /* dances based on vnode type. almost ufs_vinit(), but not quite */
132 switch (type) {
133 case VCHR:
134 case VBLK:
135 /*
136 * replace vnode operation vector with the specops vector.
137 * our user server has very little control over the node
138 * if it decides its a character or block special file
139 */
140 vp->v_op = puffs_specop_p;
141
142 /* do the standard checkalias-dance */
143 if ((nvp = checkalias(vp, rdev, mp)) != NULL) {
144 /*
145 * found: release & unallocate aliased
146 * old (well, actually, new) node
147 */
148 vp->v_op = spec_vnodeop_p;
149 vp->v_flag &= ~VLOCKSWORK;
150 vrele(vp);
151 vgone(vp); /* cya */
152
153 /* init "new" vnode */
154 vp = nvp;
155 vp->v_vnlock = NULL;
156 vp->v_mount = mp;
157 }
158 break;
159
160 case VFIFO:
161 vp->v_op = puffs_fifoop_p;
162 break;
163
164 case VREG:
165 uvm_vnp_setsize(vp, vsize);
166 break;
167
168 case VDIR:
169 case VLNK:
170 case VSOCK:
171 break;
172 default:
173 #ifdef DIAGNOSTIC
174 panic("puffs_getvnode: invalid vtype %d", type);
175 #endif
176 break;
177 }
178
179 pnode = pool_get(&puffs_pnpool, PR_WAITOK);
180 pnode->pn_cookie = cookie;
181 pnode->pn_stat = 0;
182 LIST_INSERT_HEAD(&pmp->pmp_pnodelist, pnode, pn_entries);
183 vp->v_data = pnode;
184 vp->v_type = type;
185 pnode->pn_vp = vp;
186
187 genfs_node_init(vp, &puffs_genfsops);
188 *vpp = vp;
189
190 DPRINTF(("new vnode at %p, pnode %p, cookie %p\n", vp,
191 pnode, pnode->pn_cookie));
192
193 return 0;
194 }
195
196 /* new node creating for creative vop ops (create, symlink, mkdir, mknod) */
197 int
198 puffs_newnode(struct mount *mp, struct vnode *dvp, struct vnode **vpp,
199 void *cookie, struct componentname *cnp, enum vtype type, dev_t rdev)
200 {
201 struct vnode *vp;
202 int error;
203
204 /* userspace probably has this as a NULL op */
205 if (cookie == NULL) {
206 error = EOPNOTSUPP;
207 return error;
208 }
209
210 error = puffs_getvnode(dvp->v_mount, cookie, type, 0, rdev, &vp);
211 if (error)
212 return error;
213
214 vp->v_type = type;
215 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
216 *vpp = vp;
217
218 return 0;
219 }
220
221 void
222 puffs_putvnode(struct vnode *vp)
223 {
224 struct puffs_mount *pmp;
225 struct puffs_node *pnode;
226
227 pmp = VPTOPUFFSMP(vp);
228 pnode = VPTOPP(vp);
229
230 #ifdef DIAGNOSTIC
231 if (vp->v_tag != VT_PUFFS)
232 panic("puffs_putvnode: %p not a puffs vnode", vp);
233 #endif
234
235 LIST_REMOVE(pnode, pn_entries);
236 pool_put(&puffs_pnpool, vp->v_data);
237 vp->v_data = NULL;
238
239 return;
240 }
241
242 /*
243 * Locate the in-kernel vnode based on the cookie received given
244 * from userspace. Returns a locked & referenced vnode, if found,
245 * NULL otherwise.
246 *
247 * XXX: lists, although lookup cache mostly shields us from this
248 */
249 struct vnode *
250 puffs_pnode2vnode(struct puffs_mount *pmp, void *cookie)
251 {
252 struct puffs_node *pnode;
253 struct vnode *vp;
254
255 simple_lock(&pmp->pmp_lock);
256 LIST_FOREACH(pnode, &pmp->pmp_pnodelist, pn_entries) {
257 if (pnode->pn_cookie == cookie)
258 break;
259 }
260 simple_unlock(&pmp->pmp_lock);
261 if (!pnode)
262 return NULL;
263 vp = pnode->pn_vp;
264
265 if (pnode->pn_stat & PNODE_INACTIVE) {
266 if (vget(vp, LK_EXCLUSIVE | LK_RETRY))
267 return NULL;
268 } else {
269 vref(vp);
270 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
271 }
272 return vp;
273 }
274
275 void
276 puffs_makecn(struct puffs_cn *pcn, const struct componentname *cn)
277 {
278
279 pcn->pcn_nameiop = cn->cn_nameiop;
280 pcn->pcn_flags = cn->cn_flags;
281 pcn->pcn_pid = cn->cn_lwp->l_proc->p_pid;
282 puffs_credcvt(&pcn->pcn_cred, cn->cn_cred);
283
284 (void)memcpy(&pcn->pcn_name, cn->cn_nameptr, cn->cn_namelen);
285 pcn->pcn_name[cn->cn_namelen] = '\0';
286 pcn->pcn_namelen = cn->cn_namelen;
287 }
288
289 /*
290 * Convert given credentials to struct puffs_cred for userspace.
291 */
292 void
293 puffs_credcvt(struct puffs_cred *pcr, const kauth_cred_t cred)
294 {
295
296 memset(pcr, 0, sizeof(struct puffs_cred));
297
298 if (cred == NOCRED || cred == FSCRED) {
299 pcr->pcr_type = PUFFCRED_TYPE_INTERNAL;
300 if (cred == NOCRED)
301 pcr->pcr_internal = PUFFCRED_CRED_NOCRED;
302 if (cred == FSCRED)
303 pcr->pcr_internal = PUFFCRED_CRED_FSCRED;
304 } else {
305 pcr->pcr_type = PUFFCRED_TYPE_UUC;
306 kauth_cred_to_uucred(&pcr->pcr_uuc, cred);
307 }
308 }
309
310 /*
311 * Return pid. In case the operation is coming from within the
312 * kernel without any process context, borrow the swapper's pid.
313 */
314 pid_t
315 puffs_lwp2pid(struct lwp *l)
316 {
317
318 return l ? l->l_proc->p_pid : 0;
319 }
320
321
322 static void
323 puffs_gop_size(struct vnode *vp, off_t size, off_t *eobp,
324 int flags)
325 {
326
327 *eobp = size;
328 }
329
330 static void
331 puffs_gop_markupdate(struct vnode *vp, int flags)
332 {
333 int uflags = 0;
334
335 if (flags & GOP_UPDATE_ACCESSED)
336 uflags |= PUFFS_UPDATEATIME;
337 if (flags & GOP_UPDATE_MODIFIED)
338 uflags |= PUFFS_UPDATEMTIME;
339
340 puffs_updatenode(vp, uflags);
341 }
342
343 void
344 puffs_updatenode(struct vnode *vp, int flags)
345 {
346 struct timespec ts;
347 struct puffs_vnreq_setattr *setattr_arg;
348
349 if (flags == 0)
350 return;
351
352 setattr_arg = malloc(sizeof(struct puffs_vnreq_setattr), M_PUFFS,
353 M_NOWAIT | M_ZERO);
354 if (setattr_arg == NULL)
355 return; /* 2bad */
356
357 nanotime(&ts);
358
359 VATTR_NULL(&setattr_arg->pvnr_va);
360 if (flags & PUFFS_UPDATEATIME)
361 setattr_arg->pvnr_va.va_atime = ts;
362 if (flags & PUFFS_UPDATECTIME)
363 setattr_arg->pvnr_va.va_ctime = ts;
364 if (flags & PUFFS_UPDATEMTIME)
365 setattr_arg->pvnr_va.va_mtime = ts;
366 if (flags & PUFFS_UPDATESIZE)
367 setattr_arg->pvnr_va.va_size = vp->v_size;
368
369 setattr_arg->pvnr_pid = 0;
370 puffs_credcvt(&setattr_arg->pvnr_cred, NOCRED);
371
372 /* setattr_arg ownership shifted to callee */
373 puffs_vntouser_faf(MPTOPUFFSMP(vp->v_mount), PUFFS_VN_SETATTR,
374 setattr_arg, sizeof(struct puffs_vnreq_setattr), VPTOPNC(vp));
375 }
376
377 void
378 puffs_updatevpsize(struct vnode *vp)
379 {
380 struct vattr va;
381
382 if (VOP_GETATTR(vp, &va, FSCRED, NULL))
383 return;
384
385 if (va.va_size != VNOVAL)
386 vp->v_size = va.va_size;
387 }
Cache object: b80a0eb63eb0dade5ccd14d691bf387f
|