aboutsummaryrefslogtreecommitdiffstats
path: root/module
diff options
context:
space:
mode:
authorPawel Jakub Dawidek <[email protected]>2024-01-23 15:03:48 -0800
committerBrian Behlendorf <[email protected]>2024-01-26 13:38:25 -0800
commit3425484eb907d489c315cced2a1fdea08ef03fc4 (patch)
tree4e50e9ef5c7afaf9bdc5aaffa68a31088f2580f9 /module
parent9e0304c363d7bcc2330b252299edd84a6d4dabbc (diff)
Fix file descriptor leak on pool import.
Descriptor leak can be easily reproduced by doing: # zpool import tank # sysctl kern.openfiles # zpool export tank; zpool import tank # sysctl kern.openfiles We were leaking four file descriptors on every import. Similar leak most likely existed when using file-based VDEVs. External-issue: https://reviews.freebsd.org/D43529 Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Pawel Jakub Dawidek <[email protected]> Closes #15630
Diffstat (limited to 'module')
-rw-r--r--module/os/freebsd/zfs/zfs_file_os.c63
1 files changed, 51 insertions, 12 deletions
diff --git a/module/os/freebsd/zfs/zfs_file_os.c b/module/os/freebsd/zfs/zfs_file_os.c
index 60c9ff058..f7f2be2cf 100644
--- a/module/os/freebsd/zfs/zfs_file_os.c
+++ b/module/os/freebsd/zfs/zfs_file_os.c
@@ -53,26 +53,65 @@ int
zfs_file_open(const char *path, int flags, int mode, zfs_file_t **fpp)
{
struct thread *td;
- int rc, fd;
+ struct vnode *vp;
+ struct file *fp;
+ struct nameidata nd;
+ int error;
td = curthread;
pwd_ensure_dirs();
- /* 12.x doesn't take a const char * */
- rc = kern_openat(td, AT_FDCWD, __DECONST(char *, path),
- UIO_SYSSPACE, flags, mode);
- if (rc)
- return (SET_ERROR(rc));
- fd = td->td_retval[0];
- td->td_retval[0] = 0;
- if (fget(curthread, fd, &cap_no_rights, fpp))
- kern_close(td, fd);
+
+ KASSERT((flags & (O_EXEC | O_PATH)) == 0,
+ ("invalid flags: 0x%x", flags));
+ KASSERT((flags & O_ACCMODE) != O_ACCMODE,
+ ("invalid flags: 0x%x", flags));
+ flags = FFLAGS(flags);
+
+ error = falloc_noinstall(td, &fp);
+ if (error != 0) {
+ return (error);
+ }
+ fp->f_flag = flags & FMASK;
+
+#if __FreeBSD_version >= 1400043
+ NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path);
+#else
+ NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, td);
+#endif
+ error = vn_open(&nd, &flags, mode, fp);
+ if (error != 0) {
+ falloc_abort(td, fp);
+ return (SET_ERROR(error));
+ }
+ NDFREE_PNBUF(&nd);
+ vp = nd.ni_vp;
+ fp->f_vnode = vp;
+ if (fp->f_ops == &badfileops) {
+ finit_vnode(fp, flags, NULL, &vnops);
+ }
+ VOP_UNLOCK(vp);
+ if (vp->v_type != VREG) {
+ zfs_file_close(fp);
+ return (SET_ERROR(EACCES));
+ }
+
+ if (flags & O_TRUNC) {
+ error = fo_truncate(fp, 0, td->td_ucred, td);
+ if (error != 0) {
+ zfs_file_close(fp);
+ return (SET_ERROR(error));
+ }
+ }
+
+ *fpp = fp;
+
return (0);
}
void
zfs_file_close(zfs_file_t *fp)
{
- fo_close(fp, curthread);
+ fdrop(fp, curthread);
}
static int
@@ -263,7 +302,7 @@ zfs_file_get(int fd)
void
zfs_file_put(zfs_file_t *fp)
{
- fdrop(fp, curthread);
+ zfs_file_close(fp);
}
loff_t