]> git.proxmox.com Git - mirror_zfs.git/blob - module/os/freebsd/zfs/zfs_file_os.c
9d68499d82ec932de6a2272fd20864299a0e3234
[mirror_zfs.git] / module / os / freebsd / zfs / zfs_file_os.c
1 /*
2 * Copyright (c) 2020 iXsystems, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 */
27
28 #include <sys/dmu.h>
29 #include <sys/dmu_impl.h>
30 #include <sys/dmu_recv.h>
31 #include <sys/dmu_tx.h>
32 #include <sys/dbuf.h>
33 #include <sys/dnode.h>
34 #include <sys/zfs_context.h>
35 #include <sys/dmu_objset.h>
36 #include <sys/dmu_traverse.h>
37 #include <sys/dsl_dataset.h>
38 #include <sys/dsl_dir.h>
39 #include <sys/dsl_pool.h>
40 #include <sys/dsl_synctask.h>
41 #include <sys/zfs_ioctl.h>
42 #include <sys/zap.h>
43 #include <sys/zio_checksum.h>
44 #include <sys/zfs_znode.h>
45 #include <sys/zfs_file.h>
46 #include <sys/buf.h>
47 #include <sys/stat.h>
48
49 int
50 zfs_file_open(const char *path, int flags, int mode, zfs_file_t **fpp)
51 {
52 struct thread *td;
53 int rc, fd;
54
55 td = curthread;
56 pwd_ensure_dirs();
57 /* 12.x doesn't take a const char * */
58 rc = kern_openat(td, AT_FDCWD, __DECONST(char *, path),
59 UIO_SYSSPACE, flags, mode);
60 if (rc)
61 return (SET_ERROR(rc));
62 fd = td->td_retval[0];
63 td->td_retval[0] = 0;
64 if (fget(curthread, fd, &cap_no_rights, fpp))
65 kern_close(td, fd);
66 return (0);
67 }
68
69 void
70 zfs_file_close(zfs_file_t *fp)
71 {
72 fo_close(fp, curthread);
73 }
74
75 static int
76 zfs_file_write_impl(zfs_file_t *fp, const void *buf, size_t count, loff_t *offp,
77 ssize_t *resid)
78 {
79 ssize_t rc;
80 struct uio auio;
81 struct thread *td;
82 struct iovec aiov;
83
84 td = curthread;
85 aiov.iov_base = (void *)(uintptr_t)buf;
86 aiov.iov_len = count;
87 auio.uio_iov = &aiov;
88 auio.uio_iovcnt = 1;
89 auio.uio_segflg = UIO_SYSSPACE;
90 auio.uio_resid = count;
91 auio.uio_rw = UIO_WRITE;
92 auio.uio_td = td;
93 auio.uio_offset = *offp;
94
95 if ((fp->f_flag & FWRITE) == 0)
96 return (SET_ERROR(EBADF));
97
98 if (fp->f_type == DTYPE_VNODE)
99 bwillwrite();
100
101 rc = fo_write(fp, &auio, td->td_ucred, FOF_OFFSET, td);
102 if (rc)
103 return (SET_ERROR(rc));
104 if (resid)
105 *resid = auio.uio_resid;
106 else if (auio.uio_resid)
107 return (SET_ERROR(EIO));
108 *offp += count - auio.uio_resid;
109 return (rc);
110 }
111
112 int
113 zfs_file_write(zfs_file_t *fp, const void *buf, size_t count, ssize_t *resid)
114 {
115 loff_t off = fp->f_offset;
116 ssize_t rc;
117
118 rc = zfs_file_write_impl(fp, buf, count, &off, resid);
119 if (rc == 0)
120 fp->f_offset = off;
121
122 return (SET_ERROR(rc));
123 }
124
125 int
126 zfs_file_pwrite(zfs_file_t *fp, const void *buf, size_t count, loff_t off,
127 ssize_t *resid)
128 {
129 return (zfs_file_write_impl(fp, buf, count, &off, resid));
130 }
131
132 static int
133 zfs_file_read_impl(zfs_file_t *fp, void *buf, size_t count, loff_t *offp,
134 ssize_t *resid)
135 {
136 ssize_t rc;
137 struct uio auio;
138 struct thread *td;
139 struct iovec aiov;
140
141 td = curthread;
142 aiov.iov_base = (void *)(uintptr_t)buf;
143 aiov.iov_len = count;
144 auio.uio_iov = &aiov;
145 auio.uio_iovcnt = 1;
146 auio.uio_segflg = UIO_SYSSPACE;
147 auio.uio_resid = count;
148 auio.uio_rw = UIO_READ;
149 auio.uio_td = td;
150 auio.uio_offset = *offp;
151
152 if ((fp->f_flag & FREAD) == 0)
153 return (SET_ERROR(EBADF));
154
155 rc = fo_read(fp, &auio, td->td_ucred, FOF_OFFSET, td);
156 if (rc)
157 return (SET_ERROR(rc));
158 if (resid)
159 *resid = auio.uio_resid;
160 *offp += count - auio.uio_resid;
161 return (SET_ERROR(0));
162 }
163
164 int
165 zfs_file_read(zfs_file_t *fp, void *buf, size_t count, ssize_t *resid)
166 {
167 loff_t off = fp->f_offset;
168 ssize_t rc;
169
170 rc = zfs_file_read_impl(fp, buf, count, &off, resid);
171 if (rc == 0)
172 fp->f_offset = off;
173 return (rc);
174 }
175
176 int
177 zfs_file_pread(zfs_file_t *fp, void *buf, size_t count, loff_t off,
178 ssize_t *resid)
179 {
180 return (zfs_file_read_impl(fp, buf, count, &off, resid));
181 }
182
183 int
184 zfs_file_seek(zfs_file_t *fp, loff_t *offp, int whence)
185 {
186 int rc;
187 struct thread *td;
188
189 td = curthread;
190 if ((fp->f_ops->fo_flags & DFLAG_SEEKABLE) == 0)
191 return (SET_ERROR(ESPIPE));
192 rc = fo_seek(fp, *offp, whence, td);
193 if (rc == 0)
194 *offp = td->td_uretoff.tdu_off;
195 return (SET_ERROR(rc));
196 }
197
198 int
199 zfs_file_getattr(zfs_file_t *fp, zfs_file_attr_t *zfattr)
200 {
201 struct thread *td;
202 struct stat sb;
203 int rc;
204
205 td = curthread;
206
207 #if __FreeBSD_version < 1400037
208 rc = fo_stat(fp, &sb, td->td_ucred, td);
209 #else
210 rc = fo_stat(fp, &sb, td->td_ucred);
211 #endif
212 if (rc)
213 return (SET_ERROR(rc));
214 zfattr->zfa_size = sb.st_size;
215 zfattr->zfa_mode = sb.st_mode;
216
217 return (0);
218 }
219
220 static __inline int
221 zfs_vop_fsync(vnode_t *vp)
222 {
223 struct mount *mp;
224 int error;
225
226 #if __FreeBSD_version < 1400068
227 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
228 #else
229 if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0)
230 #endif
231 goto drop;
232 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
233 error = VOP_FSYNC(vp, MNT_WAIT, curthread);
234 VOP_UNLOCK1(vp);
235 vn_finished_write(mp);
236 drop:
237 return (SET_ERROR(error));
238 }
239
240 int
241 zfs_file_fsync(zfs_file_t *fp, int flags)
242 {
243 if (fp->f_type != DTYPE_VNODE)
244 return (EINVAL);
245
246 return (zfs_vop_fsync(fp->f_vnode));
247 }
248
249 zfs_file_t *
250 zfs_file_get(int fd)
251 {
252 struct file *fp;
253
254 if (fget(curthread, fd, &cap_no_rights, &fp))
255 return (NULL);
256
257 return (fp);
258 }
259
260 void
261 zfs_file_put(zfs_file_t *fp)
262 {
263 fdrop(fp, curthread);
264 }
265
266 loff_t
267 zfs_file_off(zfs_file_t *fp)
268 {
269 return (fp->f_offset);
270 }
271
272 void *
273 zfs_file_private(zfs_file_t *fp)
274 {
275 file_t *tmpfp;
276 void *data;
277 int error;
278
279 tmpfp = curthread->td_fpop;
280 curthread->td_fpop = fp;
281 error = devfs_get_cdevpriv(&data);
282 curthread->td_fpop = tmpfp;
283 if (error != 0)
284 return (NULL);
285 return (data);
286 }
287
288 int
289 zfs_file_unlink(const char *fnamep)
290 {
291 zfs_uio_seg_t seg = UIO_SYSSPACE;
292 int rc;
293
294 #if __FreeBSD_version >= 1300018
295 rc = kern_funlinkat(curthread, AT_FDCWD, fnamep, FD_NONE, seg, 0, 0);
296 #elif __FreeBSD_version >= 1202504 || defined(AT_BENEATH)
297 rc = kern_unlinkat(curthread, AT_FDCWD, __DECONST(char *, fnamep),
298 seg, 0, 0);
299 #else
300 rc = kern_unlinkat(curthread, AT_FDCWD, __DECONST(char *, fnamep),
301 seg, 0);
302 #endif
303 return (SET_ERROR(rc));
304 }