Skip to content

Commit a4bf6ba

Browse files
authored
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
1 parent 435b173 commit a4bf6ba

File tree

1 file changed

+51
-12
lines changed

1 file changed

+51
-12
lines changed

module/os/freebsd/zfs/zfs_file_os.c

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,26 +50,65 @@ int
5050
zfs_file_open(const char *path, int flags, int mode, zfs_file_t **fpp)
5151
{
5252
struct thread *td;
53-
int rc, fd;
53+
struct vnode *vp;
54+
struct file *fp;
55+
struct nameidata nd;
56+
int error;
5457

5558
td = curthread;
5659
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);
60+
61+
KASSERT((flags & (O_EXEC | O_PATH)) == 0,
62+
("invalid flags: 0x%x", flags));
63+
KASSERT((flags & O_ACCMODE) != O_ACCMODE,
64+
("invalid flags: 0x%x", flags));
65+
flags = FFLAGS(flags);
66+
67+
error = falloc_noinstall(td, &fp);
68+
if (error != 0) {
69+
return (error);
70+
}
71+
fp->f_flag = flags & FMASK;
72+
73+
#if __FreeBSD_version >= 1400043
74+
NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path);
75+
#else
76+
NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, td);
77+
#endif
78+
error = vn_open(&nd, &flags, mode, fp);
79+
if (error != 0) {
80+
falloc_abort(td, fp);
81+
return (SET_ERROR(error));
82+
}
83+
NDFREE_PNBUF(&nd);
84+
vp = nd.ni_vp;
85+
fp->f_vnode = vp;
86+
if (fp->f_ops == &badfileops) {
87+
finit_vnode(fp, flags, NULL, &vnops);
88+
}
89+
VOP_UNLOCK(vp);
90+
if (vp->v_type != VREG) {
91+
zfs_file_close(fp);
92+
return (SET_ERROR(EACCES));
93+
}
94+
95+
if (flags & O_TRUNC) {
96+
error = fo_truncate(fp, 0, td->td_ucred, td);
97+
if (error != 0) {
98+
zfs_file_close(fp);
99+
return (SET_ERROR(error));
100+
}
101+
}
102+
103+
*fpp = fp;
104+
66105
return (0);
67106
}
68107

69108
void
70109
zfs_file_close(zfs_file_t *fp)
71110
{
72-
fo_close(fp, curthread);
111+
fdrop(fp, curthread);
73112
}
74113

75114
static int
@@ -260,7 +299,7 @@ zfs_file_get(int fd)
260299
void
261300
zfs_file_put(zfs_file_t *fp)
262301
{
263-
fdrop(fp, curthread);
302+
zfs_file_close(fp);
264303
}
265304

266305
loff_t

0 commit comments

Comments
 (0)