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 <behlendorf1@llnl.gov> Signed-off-by: Pawel Jakub Dawidek <pawel@dawidek.net> Closes #15630
This commit is contained in:
parent
435b173fd9
commit
a4bf6baaeb
|
@ -50,26 +50,65 @@ int
|
||||||
zfs_file_open(const char *path, int flags, int mode, zfs_file_t **fpp)
|
zfs_file_open(const char *path, int flags, int mode, zfs_file_t **fpp)
|
||||||
{
|
{
|
||||||
struct thread *td;
|
struct thread *td;
|
||||||
int rc, fd;
|
struct vnode *vp;
|
||||||
|
struct file *fp;
|
||||||
|
struct nameidata nd;
|
||||||
|
int error;
|
||||||
|
|
||||||
td = curthread;
|
td = curthread;
|
||||||
pwd_ensure_dirs();
|
pwd_ensure_dirs();
|
||||||
/* 12.x doesn't take a const char * */
|
|
||||||
rc = kern_openat(td, AT_FDCWD, __DECONST(char *, path),
|
KASSERT((flags & (O_EXEC | O_PATH)) == 0,
|
||||||
UIO_SYSSPACE, flags, mode);
|
("invalid flags: 0x%x", flags));
|
||||||
if (rc)
|
KASSERT((flags & O_ACCMODE) != O_ACCMODE,
|
||||||
return (SET_ERROR(rc));
|
("invalid flags: 0x%x", flags));
|
||||||
fd = td->td_retval[0];
|
flags = FFLAGS(flags);
|
||||||
td->td_retval[0] = 0;
|
|
||||||
if (fget(curthread, fd, &cap_no_rights, fpp))
|
error = falloc_noinstall(td, &fp);
|
||||||
kern_close(td, fd);
|
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);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
zfs_file_close(zfs_file_t *fp)
|
zfs_file_close(zfs_file_t *fp)
|
||||||
{
|
{
|
||||||
fo_close(fp, curthread);
|
fdrop(fp, curthread);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -260,7 +299,7 @@ zfs_file_get(int fd)
|
||||||
void
|
void
|
||||||
zfs_file_put(zfs_file_t *fp)
|
zfs_file_put(zfs_file_t *fp)
|
||||||
{
|
{
|
||||||
fdrop(fp, curthread);
|
zfs_file_close(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
loff_t
|
loff_t
|
||||||
|
|
Loading…
Reference in New Issue