2 * Copyright (c) 2019 Tomohiro Kusumi <tkusumi@netbsd.org>
3 * Copyright (c) 2019 The DragonFly Project
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
34 fuse_brelse(struct buf *bp)
36 bp->b_flags |= B_INVAL | B_RELBUF;
41 fuse_fix_size(struct fuse_node *fnp, bool fixsize, size_t oldsize)
44 fuse_node_truncate(fnp, fnp->size, oldsize);
48 fuse_read(struct vop_read_args *ap)
50 struct vnode *vp = ap->a_vp;
51 struct uio *uio = ap->a_uio;
52 struct fuse_mount *fmp = VFSTOFUSE(vp->v_mount);
53 struct fuse_node *fnp = VTOI(vp);
54 bool need_reopen = !curproc || fnp->closed; /* XXX */
57 while (uio->uio_resid > 0 && uio->uio_offset < fnp->size) {
61 struct fuse_read_in *fri;
62 off_t base_offset, buf_offset;
66 fh = fuse_nfh(VTOI(vp));
68 fh = fuse_fh(ap->a_fp);
70 buf_offset = (off_t)uio->uio_offset & FUSE_BLKMASK64;
71 base_offset = (off_t)uio->uio_offset - buf_offset;
73 fuse_dbg("uio_offset=%ju uio_resid=%ju base_offset=%ju "
75 uio->uio_offset, uio->uio_resid, base_offset, buf_offset);
77 bp = getblk(vp, base_offset, FUSE_BLKSIZE, 0, 0);
79 if ((bp->b_flags & (B_INVAL | B_CACHE | B_RAM)) == B_CACHE) {
80 bp->b_flags &= ~B_AGE;
83 if (ap->a_ioflag & IO_NRDELAY) {
88 error = breadnx(vp, base_offset, FUSE_BLKSIZE, B_NOTMETA, NULL,
92 fuse_dbg("b_loffset=%ju b_bcount=%d b_flags=%x\n",
93 bp->b_loffset, bp->b_bcount, bp->b_flags);
96 error = falloc(NULL, &fp, NULL);
101 error = VOP_OPEN(vp, FREAD | FWRITE, ap->a_cred, fp);
108 fip = fuse_ipc_get(fmp, sizeof(*fri));
109 fri = fuse_ipc_fill(fip, FUSE_READ, fnp->ino, ap->a_cred);
110 fri->offset = bp->b_loffset;
111 fri->size = bp->b_bcount;
113 fri->fh = fuse_nfh(VTOI(vp));
117 fuse_dbg("fuse_read_in offset=%ju size=%u fh=%jx\n",
118 fri->offset, fri->size, fri->fh);
120 error = fuse_ipc_tx(fip);
125 memcpy(bp->b_data, fuse_out_data(fip), fuse_out_data_size(fip));
129 error = fdrop(fp); /* calls VOP_CLOSE() */
136 len = FUSE_BLKSIZE - buf_offset;
137 if (len > uio->uio_resid)
138 len = uio->uio_resid;
139 if (uio->uio_offset + len > fnp->size)
140 len = (size_t)(fnp->size - uio->uio_offset);
141 fuse_dbg("size=%ju len=%ju\n", fnp->size, len);
143 error = uiomovebp(bp, bp->b_data + buf_offset, len, uio);
149 fuse_dbg("uio_offset=%ju uio_resid=%ju error=%d done\n",
150 uio->uio_offset, uio->uio_resid, error);
156 fuse_write(struct vop_write_args *ap)
158 return fuse_dio_write(ap);
162 fuse_dio_write(struct vop_write_args *ap)
164 struct vnode *vp = ap->a_vp;
165 struct uio *uio = ap->a_uio;
166 struct fuse_mount *fmp = VFSTOFUSE(vp->v_mount);
167 struct fuse_node *fnp = VTOI(vp);
168 bool need_reopen = !curproc || fnp->closed; /* XXX */
172 if (ap->a_ioflag & IO_APPEND)
173 uio->uio_offset = fnp->size;
175 while (uio->uio_resid > 0) {
178 struct fuse_ipc *fip;
179 struct fuse_read_in *fri;
180 struct fuse_write_in *fwi;
181 struct fuse_write_out *fwo;
182 off_t base_offset, buf_offset;
185 bool fixsize = false;
186 bool need_read = false;
188 fh = fuse_nfh(VTOI(vp));
190 fh = fuse_fh(ap->a_fp);
192 buf_offset = (off_t)uio->uio_offset & FUSE_BLKMASK64;
193 base_offset = (off_t)uio->uio_offset - buf_offset;
195 fuse_dbg("uio_offset=%ju uio_resid=%ju base_offset=%ju "
197 uio->uio_offset, uio->uio_resid, base_offset, buf_offset);
200 len = FUSE_BLKSIZE - buf_offset;
201 if (len > uio->uio_resid)
202 len = uio->uio_resid;
203 if (uio->uio_offset + len > fnp->size) {
204 /* XXX trivial flag */
205 error = fuse_node_truncate(fnp, fnp->size,
206 uio->uio_offset + len);
210 kflags |= NOTE_EXTEND;
212 fuse_dbg("size=%ju len=%ju\n", fnp->size, len);
215 if (uio->uio_segflg == UIO_NOCOPY) {
216 bp = getblk(ap->a_vp, base_offset, FUSE_BLKSIZE,
218 if (!(bp->b_flags & B_CACHE)) {
222 } else if (!buf_offset && uio->uio_resid >= FUSE_BLKSIZE) {
223 bp = getblk(ap->a_vp, base_offset, FUSE_BLKSIZE,
225 if (!(bp->b_flags & B_CACHE))
227 } else if (base_offset >= fnp->size) {
228 bp = getblk(ap->a_vp, base_offset, FUSE_BLKSIZE,
236 fuse_dbg("b_loffset=%ju b_bcount=%d b_flags=%x\n",
237 bp->b_loffset, bp->b_bcount, bp->b_flags);
240 error = falloc(NULL, &fp, NULL);
243 fuse_fix_size(fnp, fixsize, oldsize);
246 /* XXX can panic at vref() in vop_stdopen() */
247 error = VOP_OPEN(vp, FREAD | FWRITE, ap->a_cred, fp);
250 fuse_fix_size(fnp, fixsize, oldsize);
256 error = bread(ap->a_vp, base_offset, FUSE_BLKSIZE, &bp);
259 fuse_dbg("b_loffset=%ju b_bcount=%d b_flags=%x\n",
260 bp->b_loffset, bp->b_bcount, bp->b_flags);
262 if (bp->b_loffset + (buf_offset + len) > oldsize) {
263 memset(bp->b_data, 0, FUSE_BLKSIZE); /* XXX */
264 goto skip; /* prevent EBADF */
267 fip = fuse_ipc_get(fmp, sizeof(*fri));
268 fri = fuse_ipc_fill(fip, FUSE_READ, fnp->ino,
270 fri->offset = bp->b_loffset;
271 fri->size = buf_offset + len;
273 fri->fh = fuse_nfh(VTOI(vp));
277 fuse_dbg("fuse_read_in offset=%ju size=%u fh=%jx\n",
278 fri->offset, fri->size, fri->fh);
280 error = fuse_ipc_tx(fip);
283 fuse_fix_size(fnp, fixsize, oldsize);
286 memcpy(bp->b_data, fuse_out_data(fip),
287 fuse_out_data_size(fip));
291 error = uiomovebp(bp, bp->b_data + buf_offset, len, uio);
294 fuse_fix_size(fnp, fixsize, oldsize);
297 kflags |= NOTE_WRITE;
299 fip = fuse_ipc_get(fmp, sizeof(*fwi) + len);
300 fwi = fuse_ipc_fill(fip, FUSE_WRITE, fnp->ino, ap->a_cred);
301 fwi->offset = bp->b_loffset + buf_offset;
304 fwi->fh = fuse_nfh(VTOI(vp));
307 memcpy((void*)(fwi + 1), bp->b_data + buf_offset, len);
309 fuse_dbg("fuse_write_in offset=%ju size=%u fh=%jx\n",
310 fwi->offset, fwi->size, fwi->fh);
312 error = fuse_ipc_tx(fip);
315 fuse_fix_size(fnp, fixsize, oldsize);
318 fwo = fuse_out_data(fip);
319 if (fwo->size != len) {
322 fuse_fix_size(fnp, fixsize, oldsize);
328 error = fdrop(fp); /* calls VOP_CLOSE() */
331 fuse_fix_size(fnp, fixsize, oldsize);
340 fuse_knote(ap->a_vp, kflags);
342 fuse_dbg("uio_offset=%ju uio_resid=%ju error=%d done\n",
343 uio->uio_offset, uio->uio_resid, error);