Bring in the "Port PUFFS from NetBSD/FreeBSD" GSoC 2011 project results.
[dragonfly.git] / sys / vfs / puffs / puffs_subr.c
1 /*      $NetBSD: puffs_subr.c,v 1.66 2008/11/16 19:34:30 pooka Exp $    */
2
3 /*
4  * Copyright (c) 2006, 2007  Antti Kantee.  All Rights Reserved.
5  *
6  * Development of this software was supported by the
7  * Ulla Tuominen Foundation and the Finnish Cultural Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30
31 #include <sys/param.h>
32 #include <sys/buf.h>
33 #include <sys/malloc.h>
34 #include <sys/kernel.h>
35 #include <sys/mount.h>
36 #include <sys/namei.h>
37 #include <sys/poll.h>
38 #include <sys/proc.h>
39
40 #include <vfs/puffs/puffs_msgif.h>
41 #include <vfs/puffs/puffs_sys.h>
42
43 MALLOC_DEFINE(M_PUFFS, "puffs", "PUFFS");
44
45 #ifdef PUFFSDEBUG
46 int puffsdebug = 1;
47 #endif
48
49 void
50 puffs_makecn(struct puffs_kcn *pkcn, struct puffs_kcred *pkcr,
51         const struct namecache *ncp, struct ucred *cred)
52 {
53         KKASSERT(ncp->nc_nlen < sizeof(pkcn->pkcn_name));
54         pkcn->pkcn_namelen =  ncp->nc_nlen;
55         strlcpy(pkcn->pkcn_name, ncp->nc_name, sizeof(pkcn->pkcn_name));
56
57         puffs_credcvt(pkcr, cred);
58 }
59
60 /*
61  * Convert given credentials to struct puffs_kcred for userspace.
62  */
63 void
64 puffs_credcvt(struct puffs_kcred *pkcr, struct ucred *cred)
65 {
66
67         memset(pkcr, 0, sizeof(struct puffs_kcred));
68
69         if (cred == NOCRED || cred == FSCRED) {
70                 pkcr->pkcr_type = PUFFCRED_TYPE_INTERNAL;
71                 if (cred == NOCRED)
72                         pkcr->pkcr_internal = PUFFCRED_CRED_NOCRED;
73                 if (cred == FSCRED)
74                         pkcr->pkcr_internal = PUFFCRED_CRED_FSCRED;
75         } else {
76                 pkcr->pkcr_type = PUFFCRED_TYPE_UUC;
77                 cru2x(cred, &pkcr->pkcr_uuc);
78         }
79 }
80
81 void
82 puffs_parkdone_asyncbioread(struct puffs_mount *pmp,
83         struct puffs_req *preq, void *arg)
84 {
85         struct puffs_vnmsg_read *read_msg = (void *)preq;
86         struct buf *bp = arg;
87         size_t moved;
88
89         DPRINTF(("%s\n", __func__));
90
91         bp->b_error = checkerr(pmp, preq->preq_rv, __func__);
92         if (bp->b_error == 0) {
93                 if (read_msg->pvnr_resid > bp->b_bcount) {
94                         puffs_senderr(pmp, PUFFS_ERR_READ, E2BIG,
95                             "resid grew", preq->preq_cookie);
96                         bp->b_error = E2BIG;
97                 } else {
98                         moved = bp->b_bcount - read_msg->pvnr_resid;
99                         bp->b_resid = read_msg->pvnr_resid;
100
101                         memcpy(bp->b_data, read_msg->pvnr_data, moved);
102                 }
103         }
104
105         bpdone(bp, 0);
106 }
107
108 void
109 puffs_parkdone_asyncbiowrite(struct puffs_mount *pmp,
110         struct puffs_req *preq, void *arg)
111 {
112         struct puffs_vnmsg_write *write_msg = (void *)preq;
113         struct buf *bp = arg;
114
115         DPRINTF(("%s\n", __func__));
116
117         bp->b_error = checkerr(pmp, preq->preq_rv, __func__);
118         if (bp->b_error == 0) {
119                 if (write_msg->pvnr_resid > bp->b_bcount) {
120                         puffs_senderr(pmp, PUFFS_ERR_WRITE, E2BIG,
121                             "resid grew", preq->preq_cookie);
122                         bp->b_error = E2BIG;
123                 } else {
124                         bp->b_resid = write_msg->pvnr_resid;
125                 }
126         }
127
128         bpdone(bp, 0);
129 }
130
131 /* XXX: userspace can leak kernel resources */
132 void
133 puffs_parkdone_poll(struct puffs_mount *pmp, struct puffs_req *preq, void *arg)
134 {
135         struct puffs_vnmsg_poll *poll_msg = (void *)preq;
136         struct puffs_node *pn = arg;
137         int revents, error;
138
139         error = checkerr(pmp, preq->preq_rv, __func__);
140         if (error)
141                 revents = poll_msg->pvnr_events;
142         else
143                 revents = POLLERR;
144
145         lockmgr(&pn->pn_mtx, LK_EXCLUSIVE);
146         pn->pn_revents |= revents;
147         lockmgr(&pn->pn_mtx, LK_RELEASE);
148
149 #ifdef XXXDF
150         selnotify(&pn->pn_sel, revents, 0);
151 #endif
152
153         puffs_releasenode(pn);
154 }
155
156 void
157 puffs_mp_reference(struct puffs_mount *pmp)
158 {
159
160         KKASSERT(lockstatus(&pmp->pmp_lock, curthread) == LK_EXCLUSIVE);
161         pmp->pmp_refcount++;
162 }
163
164 void
165 puffs_mp_release(struct puffs_mount *pmp)
166 {
167
168         KKASSERT(lockstatus(&pmp->pmp_lock, curthread) == LK_EXCLUSIVE);
169         if (--pmp->pmp_refcount == 0)
170                 cv_broadcast(&pmp->pmp_refcount_cv);
171 }
172
173 void
174 puffs_senderr(struct puffs_mount *pmp, int type, int error,
175         const char *str, puffs_cookie_t ck)
176 {
177         struct puffs_msgpark *park;
178         struct puffs_error *perr;
179
180         puffs_msgmem_alloc(sizeof(struct puffs_error), &park, (void *)&perr, 1);
181         puffs_msg_setfaf(park);
182         puffs_msg_setinfo(park, PUFFSOP_ERROR, type, ck);
183
184         perr->perr_error = error;
185         strlcpy(perr->perr_str, str, sizeof(perr->perr_str));
186
187         puffs_msg_enqueue(pmp, park);
188         puffs_msgmem_release(park);
189 }