mirror of
				https://git.proxmox.com/git/mirror_zfs.git
				synced 2025-10-26 18:05:04 +03:00 
			
		
		
		
	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)
 | 
			
		||||
{
 | 
			
		||||
	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
 | 
			
		||||
@ -260,7 +299,7 @@ zfs_file_get(int fd)
 | 
			
		||||
void
 | 
			
		||||
zfs_file_put(zfs_file_t *fp)
 | 
			
		||||
{
 | 
			
		||||
	fdrop(fp, curthread);
 | 
			
		||||
	zfs_file_close(fp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
loff_t
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user