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
35 fuse_fix_size(struct fuse_node
*fnp
, bool fixsize
, size_t oldsize
)
38 fuse_node_truncate(fnp
, fnp
->size
, oldsize
);
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 */
53 while (uio
->uio_resid
> 0 && uio
->uio_offset
< fnp
->size
) {
57 struct fuse_read_in
*fri
;
58 off_t base_offset
, buf_offset
;
62 fh
= fuse_nfh(VTOI(vp
));
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 "
71 uio
->uio_offset
, uio
->uio_resid
, base_offset
, buf_offset
);
73 bp
= getblk(vp
, base_offset
, FUSE_BLKSIZE
, 0, 0);
75 if ((bp
->b_flags
& (B_INVAL
| B_CACHE
| B_RAM
)) == B_CACHE
) {
76 bp
->b_flags
&= ~B_AGE
;
79 if (ap
->a_ioflag
& IO_NRDELAY
) {
84 error
= breadnx(vp
, base_offset
, FUSE_BLKSIZE
, B_NOTMETA
, NULL
,
88 fuse_dbg("b_loffset=%ju b_bcount=%d b_flags=%x\n",
89 bp
->b_loffset
, bp
->b_bcount
, bp
->b_flags
);
92 error
= falloc(NULL
, &fp
, NULL
);
97 error
= VOP_OPEN(vp
, FREAD
| FWRITE
, ap
->a_cred
, &fp
);
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
;
109 fri
->fh
= fuse_nfh(VTOI(vp
));
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
);
121 memcpy(bp
->b_data
, fuse_out_data(fip
), fuse_out_data_size(fip
));
125 error
= fdrop(fp
); /* calls VOP_CLOSE() */
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
);
145 fuse_dbg("uio_offset=%ju uio_resid=%ju error=%d done\n",
146 uio
->uio_offset
, uio
->uio_resid
, 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 */
168 if (ap
->a_ioflag
& IO_APPEND
)
169 uio
->uio_offset
= fnp
->size
;
171 while (uio
->uio_resid
> 0) {
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
;
181 bool fixsize
= false;
182 bool need_read
= false;
184 fh
= fuse_nfh(VTOI(vp
));
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 "
193 uio
->uio_offset
, uio
->uio_resid
, base_offset
, buf_offset
);
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
);
206 kflags
|= NOTE_EXTEND
;
208 fuse_dbg("size=%ju len=%ju\n", fnp
->size
, len
);
211 if (uio
->uio_segflg
== UIO_NOCOPY
) {
212 bp
= getblk(ap
->a_vp
, base_offset
, FUSE_BLKSIZE
,
214 if (!(bp
->b_flags
& B_CACHE
)) {
218 } else if (!buf_offset
&& uio
->uio_resid
>= FUSE_BLKSIZE
) {
219 bp
= getblk(ap
->a_vp
, base_offset
, FUSE_BLKSIZE
,
221 if (!(bp
->b_flags
& B_CACHE
))
223 } else if (base_offset
>= fnp
->size
) {
224 bp
= getblk(ap
->a_vp
, base_offset
, FUSE_BLKSIZE
,
232 fuse_dbg("b_loffset=%ju b_bcount=%d b_flags=%x\n",
233 bp
->b_loffset
, bp
->b_bcount
, bp
->b_flags
);
236 error
= falloc(NULL
, &fp
, NULL
);
239 fuse_fix_size(fnp
, fixsize
, oldsize
);
242 /* XXX can panic at vref() in vop_stdopen() */
243 error
= VOP_OPEN(vp
, FREAD
| FWRITE
, ap
->a_cred
, &fp
);
246 fuse_fix_size(fnp
, fixsize
, oldsize
);
252 error
= bread(ap
->a_vp
, base_offset
, FUSE_BLKSIZE
, &bp
);
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
,
266 fri
->offset
= bp
->b_loffset
;
267 fri
->size
= buf_offset
+ len
;
269 fri
->fh
= fuse_nfh(VTOI(vp
));
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
);
279 fuse_fix_size(fnp
, fixsize
, oldsize
);
282 memcpy(bp
->b_data
, fuse_out_data(fip
),
283 fuse_out_data_size(fip
));
287 error
= uiomovebp(bp
, bp
->b_data
+ buf_offset
, len
, uio
);
290 fuse_fix_size(fnp
, fixsize
, oldsize
);
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
;
300 fwi
->fh
= fuse_nfh(VTOI(vp
));
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
);
311 fuse_fix_size(fnp
, fixsize
, oldsize
);
314 fwo
= fuse_out_data(fip
);
315 if (fwo
->size
!= len
) {
318 fuse_fix_size(fnp
, fixsize
, oldsize
);
324 error
= fdrop(fp
); /* calls VOP_CLOSE() */
327 fuse_fix_size(fnp
, fixsize
, oldsize
);
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
);