kernel/vfs: Remove some unused variables.
[dragonfly.git] / sys / vfs / puffs / puffs_node.c
1 /*      $NetBSD: puffs_node.c,v 1.19 2011/06/30 20:09:41 wiz Exp $      */
2
3 /*
4  * Copyright (c) 2005, 2006, 2007  Antti Kantee.  All Rights Reserved.
5  *
6  * Development of this software was supported by the
7  * Google Summer of Code program, the Ulla Tuominen Foundation
8  * and the Finnish Cultural Foundation.
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  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
20  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #include <sys/param.h>
33 #include <sys/fnv_hash.h>
34 #include <sys/malloc.h>
35 #include <sys/mount.h>
36 #include <sys/namei.h>
37 #include <sys/vnode.h>
38
39 #include <vfs/puffs/puffs_msgif.h>
40 #include <vfs/puffs/puffs_sys.h>
41
42 static __inline struct puffs_node_hashlist
43         *puffs_cookie2hashlist(struct puffs_mount *, puffs_cookie_t);
44 static struct puffs_node *puffs_cookie2pnode(struct puffs_mount *,
45                                              puffs_cookie_t);
46
47 /*
48  * Grab a vnode, intialize all the puffs-dependent stuff.
49  */
50 int
51 puffs_getvnode(struct mount *mp, puffs_cookie_t ck, enum vtype type,
52         voff_t vsize, struct vnode **vpp)
53 {
54         struct puffs_mount *pmp;
55         struct puffs_newcookie *pnc;
56         struct vnode *vp;
57         struct puffs_node *pnode;
58         struct puffs_node_hashlist *plist;
59         int error;
60
61         pmp = MPTOPUFFSMP(mp);
62
63         error = EPROTO;
64         if (type <= VNON || type >= VBAD) {
65                 puffs_senderr(pmp, PUFFS_ERR_MAKENODE, EINVAL,
66                     "bad node type", ck);
67                 goto bad;
68         }
69         if (type == VBLK || type == VCHR) {
70                 puffs_senderr(pmp, PUFFS_ERR_MAKENODE, EINVAL,
71                     "device nodes are not supported", ck);
72                 goto bad;
73         }
74         if (vsize == VNOVAL) {
75                 puffs_senderr(pmp, PUFFS_ERR_MAKENODE, EINVAL,
76                     "VNOVAL is not a valid size", ck);
77                 goto bad;
78         }
79
80         /* XXX Add VT_PUFFS */
81         error = getnewvnode(VT_SYNTH, mp, &vp, 0, 0);
82         if (error) {
83                 goto bad;
84         }
85         vp->v_type = type;
86
87         /*
88          * Creation should not fail after this point.  Or if it does,
89          * care must be taken so that VOP_INACTIVE() isn't called.
90          */
91
92         /* dances based on vnode type. almost ufs_vinit(), but not quite */
93         switch (type) {
94         case VFIFO:
95                 vp->v_ops = &mp->mnt_vn_fifo_ops;
96                 break;
97
98         case VREG:
99                 if (PUFFS_USE_PAGECACHE(pmp))
100                         vinitvmio(vp, vsize, mp->mnt_stat.f_iosize, -1);
101                 break;
102
103         case VDIR:
104         case VLNK:
105         case VSOCK:
106                 break;
107         default:
108                 panic("puffs_getvnode: invalid vtype %d", type);
109         }
110
111         pnode = kmalloc(sizeof(struct puffs_node), M_PUFFS, M_ZERO | M_WAITOK);
112
113         pnode->pn_cookie = ck;
114         pnode->pn_refcount = 1;
115
116         /* insert cookie on list, take off of interlock list */
117         lockinit(&pnode->pn_mtx, "puffs pn_mtx", 0, 0);
118 #ifdef XXXDF
119         selinit(&pnode->pn_sel);
120         knlist_init();
121 #endif
122         plist = puffs_cookie2hashlist(pmp, ck);
123         lockmgr(&pmp->pmp_lock, LK_EXCLUSIVE);
124         LIST_INSERT_HEAD(plist, pnode, pn_hashent);
125         if (ck != pmp->pmp_root_cookie) {
126                 LIST_FOREACH(pnc, &pmp->pmp_newcookie, pnc_entries) {
127                         if (pnc->pnc_cookie == ck) {
128                                 LIST_REMOVE(pnc, pnc_entries);
129                                 kfree(pnc, M_PUFFS);
130                                 break;
131                         }
132                 }
133                 KKASSERT(pnc != NULL);
134         }
135         lockmgr(&pmp->pmp_lock, LK_RELEASE);
136
137         vp->v_data = pnode;
138         vp->v_type = type;
139         pnode->pn_vp = vp;
140         pnode->pn_serversize = vsize;
141
142         *vpp = vp;
143
144         DPRINTF(("new vnode at %p, pnode %p, cookie %p\n", vp,
145             pnode, pnode->pn_cookie));
146
147         return 0;
148
149  bad:
150         /* remove staging cookie from list */
151         if (ck != pmp->pmp_root_cookie) {
152                 lockmgr(&pmp->pmp_lock, LK_EXCLUSIVE);
153                 LIST_FOREACH(pnc, &pmp->pmp_newcookie, pnc_entries) {
154                         if (pnc->pnc_cookie == ck) {
155                                 LIST_REMOVE(pnc, pnc_entries);
156                                 kfree(pnc, M_PUFFS);
157                                 break;
158                         }
159                 }
160                 KKASSERT(pnc != NULL);
161                 lockmgr(&pmp->pmp_lock, LK_RELEASE);
162         }
163
164         return error;
165 }
166
167 /* new node creating for creative vop ops (create, symlink, mkdir, mknod) */
168 int
169 puffs_newnode(struct mount *mp, struct vnode *dvp, struct vnode **vpp,
170         puffs_cookie_t ck, enum vtype type)
171 {
172         struct puffs_mount *pmp = MPTOPUFFSMP(mp);
173         struct puffs_newcookie *pnc;
174         struct vnode *vp;
175         int error;
176
177         /* userspace probably has this as a NULL op */
178         if (ck == NULL) {
179                 error = EOPNOTSUPP;
180                 return error;
181         }
182
183         /*
184          * Check for previous node with the same designation.
185          * Explicitly check the root node cookie, since it might be
186          * reclaimed from the kernel when this check is made.
187          */
188         lockmgr(&pmp->pmp_lock, LK_EXCLUSIVE);
189         if (ck == pmp->pmp_root_cookie
190             || puffs_cookie2pnode(pmp, ck) != NULL) {
191                 lockmgr(&pmp->pmp_lock, LK_RELEASE);
192                 puffs_senderr(pmp, PUFFS_ERR_MAKENODE, EEXIST,
193                     "cookie exists", ck);
194                 return EPROTO;
195         }
196
197         LIST_FOREACH(pnc, &pmp->pmp_newcookie, pnc_entries) {
198                 if (pnc->pnc_cookie == ck) {
199                         lockmgr(&pmp->pmp_lock, LK_RELEASE);
200                         puffs_senderr(pmp, PUFFS_ERR_MAKENODE, EEXIST,
201                             "newcookie exists", ck);
202                         return EPROTO;
203                 }
204         }
205         pnc = kmalloc(sizeof(struct puffs_newcookie), M_PUFFS, M_WAITOK);
206         pnc->pnc_cookie = ck;
207         LIST_INSERT_HEAD(&pmp->pmp_newcookie, pnc, pnc_entries);
208         lockmgr(&pmp->pmp_lock, LK_RELEASE);
209
210         error = puffs_getvnode(dvp->v_mount, ck, type, 0, &vp);
211         if (error)
212                 return error;
213         *vpp = vp;
214
215         return 0;
216 }
217
218 void
219 puffs_putvnode(struct vnode *vp)
220 {
221         struct puffs_node *pnode;
222
223         pnode = VPTOPP(vp);
224
225 #ifdef DIAGNOSTIC
226         if (vp->v_tag != VT_SYNTH)
227                 panic("puffs_putvnode: %p not a puffs vnode", vp);
228 #endif
229
230         puffs_releasenode(pnode);
231         vp->v_data = NULL;
232
233         return;
234 }
235
236 static __inline struct puffs_node_hashlist *
237 puffs_cookie2hashlist(struct puffs_mount *pmp, puffs_cookie_t ck)
238 {
239         uint32_t hash;
240
241         hash = fnv_32_buf(&ck, sizeof(void *), FNV1_32_INIT);
242         return &pmp->pmp_pnodehash[hash % pmp->pmp_npnodehash];
243 }
244
245 /*
246  * Translate cookie to puffs_node.  Caller must hold pmp_lock
247  * and it will be held upon return.
248  */
249 static struct puffs_node *
250 puffs_cookie2pnode(struct puffs_mount *pmp, puffs_cookie_t ck)
251 {
252         struct puffs_node_hashlist *plist;
253         struct puffs_node *pnode;
254
255         plist = puffs_cookie2hashlist(pmp, ck);
256         LIST_FOREACH(pnode, plist, pn_hashent) {
257                 if (pnode->pn_cookie == ck)
258                         break;
259         }
260
261         return pnode;
262 }
263
264 /*
265  * Make sure root vnode exists and reference it.  Does NOT lock.
266  */
267 static int
268 puffs_makeroot(struct puffs_mount *pmp)
269 {
270         struct vnode *vp;
271         int rv;
272
273         /*
274          * pmp_lock must be held if vref()'ing or vrele()'ing the
275          * root vnode.  the latter is controlled by puffs_inactive().
276          *
277          * pmp_root is set here and cleared in puffs_reclaim().
278          */
279  retry:
280         vp = pmp->pmp_root;
281         if (vp) {
282                 if (vget(vp, LK_EXCLUSIVE) == 0)
283                         return 0;
284         }
285
286         /*
287          * So, didn't have the magic root vnode available.
288          * No matter, grab another and stuff it with the cookie.
289          */
290         if ((rv = puffs_getvnode(pmp->pmp_mp, pmp->pmp_root_cookie,
291             pmp->pmp_root_vtype, pmp->pmp_root_vsize, &vp)))
292                 return rv;
293
294         /*
295          * Someone magically managed to race us into puffs_getvnode?
296          * Put our previous new vnode back and retry.
297          */
298         lockmgr(&pmp->pmp_lock, LK_EXCLUSIVE);
299         if (pmp->pmp_root) {
300                 struct puffs_node *pnode = VPTOPP(vp);
301
302                 LIST_REMOVE(pnode, pn_hashent);
303                 lockmgr(&pmp->pmp_lock, LK_RELEASE);
304                 puffs_putvnode(vp);
305                 goto retry;
306         }
307
308         /* store cache */
309         vsetflags(vp, VROOT);
310         pmp->pmp_root = vp;
311         vref(vp);
312         lockmgr(&pmp->pmp_lock, LK_RELEASE);
313
314         return 0;
315 }
316
317 /*
318  * Locate the in-kernel vnode based on the cookie received given
319  * from userspace.  Returns a vnode, if found, NULL otherwise.
320  * The parameter "lock" control whether to lock the possible or
321  * not.  Locking always might cause us to lock against ourselves
322  * in situations where we want the vnode but don't care for the
323  * vnode lock, e.g. file server issued putpages.
324  */
325 int
326 puffs_cookie2vnode(struct puffs_mount *pmp, puffs_cookie_t ck,
327         int willcreate, struct vnode **vpp)
328 {
329         struct puffs_node *pnode;
330         struct puffs_newcookie *pnc;
331         struct vnode *vp;
332         int rv;
333
334         /*
335          * Handle root in a special manner, since we want to make sure
336          * pmp_root is properly set.
337          */
338         if (ck == pmp->pmp_root_cookie) {
339                 if ((rv = puffs_makeroot(pmp)))
340                         return rv;
341                 *vpp = pmp->pmp_root;
342                 return 0;
343         }
344
345         lockmgr(&pmp->pmp_lock, LK_EXCLUSIVE);
346         pnode = puffs_cookie2pnode(pmp, ck);
347         if (pnode == NULL) {
348                 if (willcreate) {
349                         pnc = kmalloc(sizeof(struct puffs_newcookie),
350                             M_PUFFS, M_WAITOK);
351                         pnc->pnc_cookie = ck;
352                         LIST_INSERT_HEAD(&pmp->pmp_newcookie, pnc, pnc_entries);
353                 }
354                 lockmgr(&pmp->pmp_lock, LK_RELEASE);
355                 return PUFFS_NOSUCHCOOKIE;
356         }
357         vp = pnode->pn_vp;
358         vhold(vp);
359         lockmgr(&pmp->pmp_lock, LK_RELEASE);
360
361         rv = vget(vp, LK_EXCLUSIVE);
362         vdrop(vp);
363         if (rv)
364                 return rv;
365
366         *vpp = vp;
367         return 0;
368 }
369
370 void
371 puffs_updatenode(struct puffs_node *pn, int flags)
372 {
373         struct timespec ts;
374
375         if (flags == 0)
376                 return;
377
378         nanotime(&ts);
379
380         if (flags & PUFFS_UPDATEATIME) {
381                 pn->pn_mc_atime = ts;
382                 pn->pn_stat |= PNODE_METACACHE_ATIME;
383         }
384         if (flags & PUFFS_UPDATECTIME) {
385                 pn->pn_mc_ctime = ts;
386                 pn->pn_stat |= PNODE_METACACHE_CTIME;
387         }
388         if (flags & PUFFS_UPDATEMTIME) {
389                 pn->pn_mc_mtime = ts;
390                 pn->pn_stat |= PNODE_METACACHE_MTIME;
391         }
392 }
393
394 int
395 puffs_meta_setsize(struct vnode *vp, off_t nsize, int trivial)
396 {
397         struct puffs_node *pn = VPTOPP(vp);
398         struct puffs_mount *pmp = VPTOPUFFSMP(vp);
399         int biosize = vp->v_mount->mnt_stat.f_iosize;
400         off_t osize;
401         int error;
402
403         osize = puffs_meta_getsize(vp);
404         pn->pn_mc_size = nsize;
405         if (pn->pn_serversize != nsize)
406                 pn->pn_stat |= PNODE_METACACHE_SIZE;
407         else
408                 pn->pn_stat &= ~PNODE_METACACHE_SIZE;
409
410         if (!PUFFS_USE_PAGECACHE(pmp))
411                 return 0;
412
413         if (nsize < osize) {
414                 error = nvtruncbuf(vp, nsize, biosize, -1, 0);
415         } else {
416                 error = nvextendbuf(vp, osize, nsize,
417                                     biosize, biosize, -1, -1,
418                                     trivial);
419         }
420
421         return error;
422 }
423
424 /*
425  * Add reference to node.
426  *  mutex held on entry and return
427  */
428 void
429 puffs_referencenode(struct puffs_node *pn)
430 {
431
432         KKASSERT(lockstatus(&pn->pn_mtx, curthread) == LK_EXCLUSIVE);
433         pn->pn_refcount++;
434 }
435
436 /*
437  * Release pnode structure which dealing with references to the
438  * puffs_node instead of the vnode.  Can't use vref()/vrele() on
439  * the vnode there, since that causes the lovely VOP_INACTIVE(),
440  * which in turn causes the lovely deadlock when called by the one
441  * who is supposed to handle it.
442  */
443 void
444 puffs_releasenode(struct puffs_node *pn)
445 {
446
447         lockmgr(&pn->pn_mtx, LK_EXCLUSIVE);
448         if (--pn->pn_refcount == 0) {
449                 lockmgr(&pn->pn_mtx, LK_RELEASE);
450                 lockuninit(&pn->pn_mtx);
451 #ifdef XXXDF
452                 seldestroy(&pn->pn_sel);
453 #endif
454                 kfree(pn, M_PUFFS);
455         } else {
456                 lockmgr(&pn->pn_mtx, LK_RELEASE);
457         }
458 }