nrelease - fix/improve livecd
[dragonfly.git] / sys / vfs / fuse / fuse_io.c
blob1d58b84ec74cdda2f8110341923eec5da27d78a6
1 /*-
2 * Copyright (c) 2019 Tomohiro Kusumi <tkusumi@netbsd.org>
3 * Copyright (c) 2019 The DragonFly Project
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
28 #include "fuse.h"
30 #include <sys/uio.h>
31 #include <sys/buf2.h>
33 #if 0
34 static void
35 fuse_fix_size(struct fuse_node *fnp, bool fixsize, size_t oldsize)
37 if (fixsize)
38 fuse_node_truncate(fnp, fnp->size, oldsize);
40 #endif
42 #if 0
43 int
44 fuse_read(struct vop_read_args *ap)
46 struct vnode *vp = ap->a_vp;
47 struct uio *uio = ap->a_uio;
48 struct fuse_mount *fmp = VFSTOFUSE(vp->v_mount);
49 struct fuse_node *fnp = VTOI(vp);
50 bool need_reopen = !curproc || fnp->closed; /* XXX */
51 int error = 0;
53 while (uio->uio_resid > 0 && uio->uio_offset < fnp->size) {
54 struct file *fp;
55 struct buf *bp;
56 struct fuse_ipc *fip;
57 struct fuse_read_in *fri;
58 off_t base_offset, buf_offset;
59 size_t len;
60 uint64_t fh;
62 fh = fuse_nfh(VTOI(vp));
63 if (ap->a_fp)
64 fh = fuse_fh(ap->a_fp);
66 buf_offset = (off_t)uio->uio_offset & FUSE_BLKMASK64;
67 base_offset = (off_t)uio->uio_offset - buf_offset;
69 fuse_dbg("uio_offset=%ju uio_resid=%ju base_offset=%ju "
70 "buf_offset=%ju\n",
71 uio->uio_offset, uio->uio_resid, base_offset, buf_offset);
73 bp = getblk(vp, base_offset, FUSE_BLKSIZE, 0, 0);
74 KKASSERT(bp);
75 if ((bp->b_flags & (B_INVAL | B_CACHE | B_RAM)) == B_CACHE) {
76 bp->b_flags &= ~B_AGE;
77 goto skip;
79 if (ap->a_ioflag & IO_NRDELAY) {
80 bqrelse(bp);
81 return EWOULDBLOCK;
84 error = breadnx(vp, base_offset, FUSE_BLKSIZE, B_NOTMETA, NULL,
85 NULL, 0, &bp);
86 KKASSERT(!error);
88 fuse_dbg("b_loffset=%ju b_bcount=%d b_flags=%x\n",
89 bp->b_loffset, bp->b_bcount, bp->b_flags);
91 if (need_reopen) {
92 error = falloc(NULL, &fp, NULL);
93 if (error) {
94 fuse_brelse(bp);
95 break;
97 error = VOP_OPEN(vp, FREAD | FWRITE, ap->a_cred, &fp);
98 if (error) {
99 fuse_brelse(bp);
100 break;
104 fip = fuse_ipc_get(fmp, sizeof(*fri));
105 fri = fuse_ipc_fill(fip, FUSE_READ, fnp->ino, ap->a_cred);
106 fri->offset = bp->b_loffset;
107 fri->size = bp->b_bcount;
108 if (need_reopen)
109 fri->fh = fuse_nfh(VTOI(vp));
110 else
111 fri->fh = fh;
113 fuse_dbg("fuse_read_in offset=%ju size=%u fh=%jx\n",
114 fri->offset, fri->size, fri->fh);
116 error = fuse_ipc_tx(fip);
117 if (error) {
118 fuse_brelse(bp);
119 break;
121 memcpy(bp->b_data, fuse_out_data(fip), fuse_out_data_size(fip));
122 fuse_ipc_put(fip);
124 if (need_reopen) {
125 error = fdrop(fp); /* calls VOP_CLOSE() */
126 if (error) {
127 fuse_brelse(bp);
128 break;
131 skip:
132 len = FUSE_BLKSIZE - buf_offset;
133 if (len > uio->uio_resid)
134 len = uio->uio_resid;
135 if (uio->uio_offset + len > fnp->size)
136 len = (size_t)(fnp->size - uio->uio_offset);
137 fuse_dbg("size=%ju len=%ju\n", fnp->size, len);
139 error = uiomovebp(bp, bp->b_data + buf_offset, len, uio);
140 bqrelse(bp);
141 if (error)
142 break;
145 fuse_dbg("uio_offset=%ju uio_resid=%ju error=%d done\n",
146 uio->uio_offset, uio->uio_resid, error);
148 return error;
152 fuse_write(struct vop_write_args *ap)
154 return fuse_dio_write(ap);
158 fuse_dio_write(struct vop_write_args *ap)
160 struct vnode *vp = ap->a_vp;
161 struct uio *uio = ap->a_uio;
162 struct fuse_mount *fmp = VFSTOFUSE(vp->v_mount);
163 struct fuse_node *fnp = VTOI(vp);
164 bool need_reopen = !curproc || fnp->closed; /* XXX */
165 int kflags = 0;
166 int error = 0;
168 if (ap->a_ioflag & IO_APPEND)
169 uio->uio_offset = fnp->size;
171 while (uio->uio_resid > 0) {
172 struct file *fp;
173 struct buf *bp;
174 struct fuse_ipc *fip;
175 struct fuse_read_in *fri;
176 struct fuse_write_in *fwi;
177 struct fuse_write_out *fwo;
178 off_t base_offset, buf_offset;
179 size_t len, oldsize;
180 uint64_t fh;
181 bool fixsize = false;
182 bool need_read = false;
184 fh = fuse_nfh(VTOI(vp));
185 if (ap->a_fp)
186 fh = fuse_fh(ap->a_fp);
188 buf_offset = (off_t)uio->uio_offset & FUSE_BLKMASK64;
189 base_offset = (off_t)uio->uio_offset - buf_offset;
191 fuse_dbg("uio_offset=%ju uio_resid=%ju base_offset=%ju "
192 "buf_offset=%ju\n",
193 uio->uio_offset, uio->uio_resid, base_offset, buf_offset);
195 oldsize = fnp->size;
196 len = FUSE_BLKSIZE - buf_offset;
197 if (len > uio->uio_resid)
198 len = uio->uio_resid;
199 if (uio->uio_offset + len > fnp->size) {
200 /* XXX trivial flag */
201 error = fuse_node_truncate(fnp, fnp->size,
202 uio->uio_offset + len);
203 if (error)
204 break;
205 fixsize = true;
206 kflags |= NOTE_EXTEND;
208 fuse_dbg("size=%ju len=%ju\n", fnp->size, len);
210 bp = NULL;
211 if (uio->uio_segflg == UIO_NOCOPY) {
212 bp = getblk(ap->a_vp, base_offset, FUSE_BLKSIZE,
213 GETBLK_BHEAVY, 0);
214 if (!(bp->b_flags & B_CACHE)) {
215 bqrelse(bp);
216 need_read = true;
218 } else if (!buf_offset && uio->uio_resid >= FUSE_BLKSIZE) {
219 bp = getblk(ap->a_vp, base_offset, FUSE_BLKSIZE,
220 GETBLK_BHEAVY, 0);
221 if (!(bp->b_flags & B_CACHE))
222 vfs_bio_clrbuf(bp);
223 } else if (base_offset >= fnp->size) {
224 bp = getblk(ap->a_vp, base_offset, FUSE_BLKSIZE,
225 GETBLK_BHEAVY, 0);
226 vfs_bio_clrbuf(bp);
227 } else {
228 need_read = true;
231 if (bp)
232 fuse_dbg("b_loffset=%ju b_bcount=%d b_flags=%x\n",
233 bp->b_loffset, bp->b_bcount, bp->b_flags);
235 if (need_reopen) {
236 error = falloc(NULL, &fp, NULL);
237 if (error) {
238 fuse_brelse(bp);
239 fuse_fix_size(fnp, fixsize, oldsize);
240 break;
242 /* XXX can panic at vref() in vop_stdopen() */
243 error = VOP_OPEN(vp, FREAD | FWRITE, ap->a_cred, &fp);
244 if (error) {
245 fuse_brelse(bp);
246 fuse_fix_size(fnp, fixsize, oldsize);
247 break;
251 if (need_read) {
252 error = bread(ap->a_vp, base_offset, FUSE_BLKSIZE, &bp);
253 KKASSERT(!error);
255 fuse_dbg("b_loffset=%ju b_bcount=%d b_flags=%x\n",
256 bp->b_loffset, bp->b_bcount, bp->b_flags);
258 if (bp->b_loffset + (buf_offset + len) > oldsize) {
259 memset(bp->b_data, 0, FUSE_BLKSIZE); /* XXX */
260 goto skip; /* prevent EBADF */
263 fip = fuse_ipc_get(fmp, sizeof(*fri));
264 fri = fuse_ipc_fill(fip, FUSE_READ, fnp->ino,
265 ap->a_cred);
266 fri->offset = bp->b_loffset;
267 fri->size = buf_offset + len;
268 if (need_reopen)
269 fri->fh = fuse_nfh(VTOI(vp));
270 else
271 fri->fh = fh;
273 fuse_dbg("fuse_read_in offset=%ju size=%u fh=%jx\n",
274 fri->offset, fri->size, fri->fh);
276 error = fuse_ipc_tx(fip);
277 if (error) {
278 fuse_brelse(bp);
279 fuse_fix_size(fnp, fixsize, oldsize);
280 break;
282 memcpy(bp->b_data, fuse_out_data(fip),
283 fuse_out_data_size(fip));
284 fuse_ipc_put(fip);
286 skip:
287 error = uiomovebp(bp, bp->b_data + buf_offset, len, uio);
288 if (error) {
289 bqrelse(bp);
290 fuse_fix_size(fnp, fixsize, oldsize);
291 break;
293 kflags |= NOTE_WRITE;
295 fip = fuse_ipc_get(fmp, sizeof(*fwi) + len);
296 fwi = fuse_ipc_fill(fip, FUSE_WRITE, fnp->ino, ap->a_cred);
297 fwi->offset = bp->b_loffset + buf_offset;
298 fwi->size = len;
299 if (need_reopen)
300 fwi->fh = fuse_nfh(VTOI(vp));
301 else
302 fwi->fh = fh;
303 memcpy((void*)(fwi + 1), bp->b_data + buf_offset, len);
305 fuse_dbg("fuse_write_in offset=%ju size=%u fh=%jx\n",
306 fwi->offset, fwi->size, fwi->fh);
308 error = fuse_ipc_tx(fip);
309 if (error) {
310 fuse_brelse(bp);
311 fuse_fix_size(fnp, fixsize, oldsize);
312 break;
314 fwo = fuse_out_data(fip);
315 if (fwo->size != len) {
316 fuse_ipc_put(fip);
317 fuse_brelse(bp);
318 fuse_fix_size(fnp, fixsize, oldsize);
319 break;
321 fuse_ipc_put(fip);
323 if (need_reopen) {
324 error = fdrop(fp); /* calls VOP_CLOSE() */
325 if (error) {
326 fuse_brelse(bp);
327 fuse_fix_size(fnp, fixsize, oldsize);
328 break;
332 error = bwrite(bp);
333 KKASSERT(!error);
336 fuse_knote(ap->a_vp, kflags);
338 fuse_dbg("uio_offset=%ju uio_resid=%ju error=%d done\n",
339 uio->uio_offset, uio->uio_resid, error);
341 return error;
343 #endif