]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - module/os/freebsd/zfs/zfs_file_os.c
Vendor import of openzfs master @ 184df27eef0abdc7ab2105b21257f753834b936b
[FreeBSD/FreeBSD.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/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <sys/dmu.h>
32 #include <sys/dmu_impl.h>
33 #include <sys/dmu_recv.h>
34 #include <sys/dmu_tx.h>
35 #include <sys/dbuf.h>
36 #include <sys/dnode.h>
37 #include <sys/zfs_context.h>
38 #include <sys/dmu_objset.h>
39 #include <sys/dmu_traverse.h>
40 #include <sys/dsl_dataset.h>
41 #include <sys/dsl_dir.h>
42 #include <sys/dsl_pool.h>
43 #include <sys/dsl_synctask.h>
44 #include <sys/zfs_ioctl.h>
45 #include <sys/zap.h>
46 #include <sys/zio_checksum.h>
47 #include <sys/zfs_znode.h>
48 #include <sys/zfs_file.h>
49 #include <sys/buf.h>
50 #include <sys/stat.h>
51
52 int
53 zfs_file_open(const char *path, int flags, int mode, zfs_file_t **fpp)
54 {
55         struct thread *td;
56         int rc, fd;
57
58         td = curthread;
59         pwd_ensure_dirs();
60         /* 12.x doesn't take a const char * */
61         rc = kern_openat(td, AT_FDCWD, __DECONST(char *, path),
62             UIO_SYSSPACE, flags, mode);
63         if (rc)
64                 return (SET_ERROR(rc));
65         fd = td->td_retval[0];
66         td->td_retval[0] = 0;
67         if (fget(curthread, fd, &cap_no_rights, fpp))
68                 kern_close(td, fd);
69         return (0);
70 }
71
72 void
73 zfs_file_close(zfs_file_t *fp)
74 {
75         fo_close(fp, curthread);
76 }
77
78 static int
79 zfs_file_write_impl(zfs_file_t *fp, const void *buf, size_t count, loff_t *offp,
80     ssize_t *resid)
81 {
82         ssize_t rc;
83         struct uio auio;
84         struct thread *td;
85         struct iovec aiov;
86
87         td = curthread;
88         aiov.iov_base = (void *)(uintptr_t)buf;
89         aiov.iov_len = count;
90         auio.uio_iov = &aiov;
91         auio.uio_iovcnt = 1;
92         auio.uio_segflg = UIO_SYSSPACE;
93         auio.uio_resid = count;
94         auio.uio_rw = UIO_WRITE;
95         auio.uio_td = td;
96         auio.uio_offset = *offp;
97
98         if ((fp->f_flag & FWRITE) == 0)
99                 return (SET_ERROR(EBADF));
100
101         if (fp->f_type == DTYPE_VNODE)
102                 bwillwrite();
103
104         rc = fo_write(fp, &auio, td->td_ucred, FOF_OFFSET, td);
105         if (rc)
106                 return (SET_ERROR(rc));
107         if (resid)
108                 *resid = auio.uio_resid;
109         else if (auio.uio_resid)
110                 return (SET_ERROR(EIO));
111         *offp += count - auio.uio_resid;
112         return (rc);
113 }
114
115 int
116 zfs_file_write(zfs_file_t *fp, const void *buf, size_t count, ssize_t *resid)
117 {
118         loff_t off = fp->f_offset;
119         ssize_t rc;
120
121         rc = zfs_file_write_impl(fp, buf, count, &off, resid);
122         if (rc == 0)
123                 fp->f_offset = off;
124
125         return (SET_ERROR(rc));
126 }
127
128 int
129 zfs_file_pwrite(zfs_file_t *fp, const void *buf, size_t count, loff_t off,
130     ssize_t *resid)
131 {
132         return (zfs_file_write_impl(fp, buf, count, &off, resid));
133 }
134
135 static int
136 zfs_file_read_impl(zfs_file_t *fp, void *buf, size_t count, loff_t *offp,
137     ssize_t *resid)
138 {
139         ssize_t rc;
140         struct uio auio;
141         struct thread *td;
142         struct iovec aiov;
143
144         td = curthread;
145         aiov.iov_base = (void *)(uintptr_t)buf;
146         aiov.iov_len = count;
147         auio.uio_iov = &aiov;
148         auio.uio_iovcnt = 1;
149         auio.uio_segflg = UIO_SYSSPACE;
150         auio.uio_resid = count;
151         auio.uio_rw = UIO_READ;
152         auio.uio_td = td;
153         auio.uio_offset = *offp;
154
155         if ((fp->f_flag & FREAD) == 0)
156                 return (SET_ERROR(EBADF));
157
158         rc = fo_read(fp, &auio, td->td_ucred, FOF_OFFSET, td);
159         if (rc)
160                 return (SET_ERROR(rc));
161         *resid = auio.uio_resid;
162         *offp += count - auio.uio_resid;
163         return (SET_ERROR(0));
164 }
165
166 int
167 zfs_file_read(zfs_file_t *fp, void *buf, size_t count, ssize_t *resid)
168 {
169         loff_t off = fp->f_offset;
170         ssize_t rc;
171
172         rc = zfs_file_read_impl(fp, buf, count, &off, resid);
173         if (rc == 0)
174                 fp->f_offset = off;
175         return (rc);
176 }
177
178 int
179 zfs_file_pread(zfs_file_t *fp, void *buf, size_t count, loff_t off,
180     ssize_t *resid)
181 {
182         return (zfs_file_read_impl(fp, buf, count, &off, resid));
183 }
184
185 int
186 zfs_file_seek(zfs_file_t *fp, loff_t *offp, int whence)
187 {
188         int rc;
189         struct thread *td;
190
191         td = curthread;
192         if ((fp->f_ops->fo_flags & DFLAG_SEEKABLE) == 0)
193                 return (SET_ERROR(ESPIPE));
194         rc = fo_seek(fp, *offp, whence, td);
195         if (rc == 0)
196                 *offp = td->td_uretoff.tdu_off;
197         return (SET_ERROR(rc));
198 }
199
200 int
201 zfs_file_getattr(zfs_file_t *fp, zfs_file_attr_t *zfattr)
202 {
203         struct thread *td;
204         struct stat sb;
205         int rc;
206
207         td = curthread;
208
209         rc = fo_stat(fp, &sb, td->td_ucred, td);
210         if (rc)
211                 return (SET_ERROR(rc));
212         zfattr->zfa_size = sb.st_size;
213         zfattr->zfa_mode = sb.st_mode;
214
215         return (0);
216 }
217
218 static __inline int
219 zfs_vop_fsync(vnode_t *vp)
220 {
221         struct mount *mp;
222         int error;
223
224         if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
225                 goto drop;
226         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
227         error = VOP_FSYNC(vp, MNT_WAIT, curthread);
228         VOP_UNLOCK1(vp);
229         vn_finished_write(mp);
230 drop:
231         return (SET_ERROR(error));
232 }
233
234 int
235 zfs_file_fsync(zfs_file_t *fp, int flags)
236 {
237         struct vnode *v;
238
239         if (fp->f_type != DTYPE_VNODE)
240                 return (EINVAL);
241
242         v = fp->f_data;
243         return (zfs_vop_fsync(v));
244 }
245
246 int
247 zfs_file_get(int fd, zfs_file_t **fpp)
248 {
249         struct file *fp;
250
251         if (fget(curthread, fd, &cap_no_rights, &fp))
252                 return (SET_ERROR(EBADF));
253
254         *fpp = fp;
255         return (0);
256 }
257
258 void
259 zfs_file_put(int fd)
260 {
261         struct file *fp;
262
263         /* No CAP_ rights required, as we're only releasing. */
264         if (fget(curthread, fd, &cap_no_rights, &fp) == 0) {
265                 fdrop(fp, curthread);
266                 fdrop(fp, curthread);
267         }
268 }
269
270 loff_t
271 zfs_file_off(zfs_file_t *fp)
272 {
273         return (fp->f_offset);
274 }
275
276 void *
277 zfs_file_private(zfs_file_t *fp)
278 {
279         file_t *tmpfp;
280         void *data;
281         int error;
282
283         tmpfp = curthread->td_fpop;
284         curthread->td_fpop = fp;
285         error = devfs_get_cdevpriv(&data);
286         curthread->td_fpop = tmpfp;
287         if (error != 0)
288                 return (NULL);
289         return (data);
290 }
291
292 int
293 zfs_file_unlink(const char *fnamep)
294 {
295         enum uio_seg seg = UIO_SYSSPACE;
296         int rc;
297
298 #if __FreeBSD_version >= 1300018
299         rc = kern_funlinkat(curthread, AT_FDCWD, fnamep, FD_NONE, seg, 0, 0);
300 #else
301 #ifdef AT_BENEATH
302         rc = kern_unlinkat(curthread, AT_FDCWD, fnamep, seg, 0, 0);
303 #else
304         rc = kern_unlinkat(curthread, AT_FDCWD, __DECONST(char *, fnamep),
305             seg, 0);
306 #endif
307 #endif
308         return (SET_ERROR(rc));
309 }