1 | /* $NetBSD: puffs_subr.c,v 1.67 2014/11/10 18:46:33 maxv 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/cdefs.h> |
32 | __KERNEL_RCSID(0, "$NetBSD: puffs_subr.c,v 1.67 2014/11/10 18:46:33 maxv Exp $" ); |
33 | |
34 | #include <sys/param.h> |
35 | #include <sys/buf.h> |
36 | #include <sys/mount.h> |
37 | #include <sys/namei.h> |
38 | #include <sys/poll.h> |
39 | #include <sys/proc.h> |
40 | |
41 | #include <fs/puffs/puffs_msgif.h> |
42 | #include <fs/puffs/puffs_sys.h> |
43 | |
44 | #ifdef PUFFSDEBUG |
45 | int puffsdebug; |
46 | #endif |
47 | |
48 | void |
49 | puffs_makecn(struct puffs_kcn *pkcn, struct puffs_kcred *pkcr, |
50 | const struct componentname *cn, int full) |
51 | { |
52 | |
53 | pkcn->pkcn_nameiop = cn->cn_nameiop; |
54 | pkcn->pkcn_flags = cn->cn_flags; |
55 | |
56 | if (full) { |
57 | (void)strcpy(pkcn->pkcn_name, cn->cn_nameptr); |
58 | } else { |
59 | (void)memcpy(pkcn->pkcn_name, cn->cn_nameptr, cn->cn_namelen); |
60 | pkcn->pkcn_name[cn->cn_namelen] = '\0'; |
61 | } |
62 | pkcn->pkcn_namelen = cn->cn_namelen; |
63 | pkcn->pkcn_consume = 0; |
64 | |
65 | puffs_credcvt(pkcr, cn->cn_cred); |
66 | } |
67 | |
68 | /* |
69 | * Convert given credentials to struct puffs_kcred for userspace. |
70 | */ |
71 | void |
72 | puffs_credcvt(struct puffs_kcred *pkcr, const kauth_cred_t cred) |
73 | { |
74 | |
75 | memset(pkcr, 0, sizeof(struct puffs_kcred)); |
76 | |
77 | if (cred == NOCRED || cred == FSCRED) { |
78 | pkcr->pkcr_type = PUFFCRED_TYPE_INTERNAL; |
79 | if (cred == NOCRED) |
80 | pkcr->pkcr_internal = PUFFCRED_CRED_NOCRED; |
81 | if (cred == FSCRED) |
82 | pkcr->pkcr_internal = PUFFCRED_CRED_FSCRED; |
83 | } else { |
84 | pkcr->pkcr_type = PUFFCRED_TYPE_UUC; |
85 | kauth_cred_to_uucred(&pkcr->pkcr_uuc, cred); |
86 | } |
87 | } |
88 | |
89 | void |
90 | puffs_parkdone_asyncbioread(struct puffs_mount *pmp, |
91 | struct puffs_req *preq, void *arg) |
92 | { |
93 | struct puffs_vnmsg_read *read_msg = (void *)preq; |
94 | struct buf *bp = arg; |
95 | size_t moved; |
96 | |
97 | DPRINTF(("%s\n" , __func__)); |
98 | |
99 | bp->b_error = checkerr(pmp, preq->preq_rv, __func__); |
100 | if (bp->b_error == 0) { |
101 | if (read_msg->pvnr_resid > bp->b_bcount) { |
102 | puffs_senderr(pmp, PUFFS_ERR_READ, E2BIG, |
103 | "resid grew" , preq->preq_cookie); |
104 | bp->b_error = E2BIG; |
105 | } else { |
106 | moved = bp->b_bcount - read_msg->pvnr_resid; |
107 | bp->b_resid = read_msg->pvnr_resid; |
108 | |
109 | memcpy(bp->b_data, read_msg->pvnr_data, moved); |
110 | } |
111 | } |
112 | |
113 | biodone(bp); |
114 | } |
115 | |
116 | void |
117 | puffs_parkdone_asyncbiowrite(struct puffs_mount *pmp, |
118 | struct puffs_req *preq, void *arg) |
119 | { |
120 | struct puffs_vnmsg_write *write_msg = (void *)preq; |
121 | struct buf *bp = arg; |
122 | |
123 | DPRINTF(("%s\n" , __func__)); |
124 | |
125 | bp->b_error = checkerr(pmp, preq->preq_rv, __func__); |
126 | if (bp->b_error == 0) { |
127 | if (write_msg->pvnr_resid > bp->b_bcount) { |
128 | puffs_senderr(pmp, PUFFS_ERR_WRITE, E2BIG, |
129 | "resid grew" , preq->preq_cookie); |
130 | bp->b_error = E2BIG; |
131 | } else { |
132 | bp->b_resid = write_msg->pvnr_resid; |
133 | } |
134 | } |
135 | |
136 | biodone(bp); |
137 | } |
138 | |
139 | /* XXX: userspace can leak kernel resources */ |
140 | void |
141 | puffs_parkdone_poll(struct puffs_mount *pmp, struct puffs_req *preq, void *arg) |
142 | { |
143 | struct puffs_vnmsg_poll *poll_msg = (void *)preq; |
144 | struct puffs_node *pn = arg; |
145 | int revents, error; |
146 | |
147 | error = checkerr(pmp, preq->preq_rv, __func__); |
148 | if (error) |
149 | revents = poll_msg->pvnr_events; |
150 | else |
151 | revents = POLLERR; |
152 | |
153 | mutex_enter(&pn->pn_mtx); |
154 | pn->pn_revents |= revents; |
155 | mutex_exit(&pn->pn_mtx); |
156 | |
157 | selnotify(&pn->pn_sel, revents, 0); |
158 | |
159 | puffs_releasenode(pn); |
160 | } |
161 | |
162 | void |
163 | puffs_mp_reference(struct puffs_mount *pmp) |
164 | { |
165 | |
166 | KASSERT(mutex_owned(&pmp->pmp_lock)); |
167 | pmp->pmp_refcount++; |
168 | } |
169 | |
170 | void |
171 | puffs_mp_release(struct puffs_mount *pmp) |
172 | { |
173 | |
174 | KASSERT(mutex_owned(&pmp->pmp_lock)); |
175 | if (--pmp->pmp_refcount == 0) |
176 | cv_broadcast(&pmp->pmp_refcount_cv); |
177 | } |
178 | |
179 | void |
180 | puffs_gop_size(struct vnode *vp, off_t size, off_t *eobp, |
181 | int flags) |
182 | { |
183 | |
184 | *eobp = size; |
185 | } |
186 | |
187 | void |
188 | puffs_gop_markupdate(struct vnode *vp, int flags) |
189 | { |
190 | int uflags = 0; |
191 | |
192 | if (flags & GOP_UPDATE_ACCESSED) |
193 | uflags |= PUFFS_UPDATEATIME; |
194 | if (flags & GOP_UPDATE_MODIFIED) |
195 | uflags |= PUFFS_UPDATEMTIME; |
196 | |
197 | puffs_updatenode(VPTOPP(vp), uflags, 0); |
198 | } |
199 | |
200 | void |
201 | puffs_senderr(struct puffs_mount *pmp, int type, int error, |
202 | const char *str, puffs_cookie_t ck) |
203 | { |
204 | struct puffs_msgpark *park; |
205 | struct puffs_error *perr; |
206 | |
207 | puffs_msgmem_alloc(sizeof(struct puffs_error), &park, (void *)&perr, 1); |
208 | puffs_msg_setfaf(park); |
209 | puffs_msg_setinfo(park, PUFFSOP_ERROR, type, ck); |
210 | |
211 | perr->perr_error = error; |
212 | strlcpy(perr->perr_str, str, sizeof(perr->perr_str)); |
213 | |
214 | puffs_msg_enqueue(pmp, park); |
215 | puffs_msgmem_release(park); |
216 | } |
217 | |