249 lines
8.6 KiB
Diff
249 lines
8.6 KiB
Diff
From ae19e57d309303b4f8e16ea26dbe6c6c7fd04f7d Mon Sep 17 00:00:00 2001
|
|
From: chenjiayi <chenjiayi22@huawei.com>
|
|
Date: Tue, 27 Jun 2023 13:57:20 +0800
|
|
Subject: [PATCH] fix(devmaster): deal with fd leak
|
|
|
|
RawFd will not be automatically closed when it is dropped. Use std::fs::File
|
|
or nix::dir::Dir to take the RawFd when opening the file or directory, which
|
|
can automatically close the RawFd when the variable is dropped.
|
|
|
|
Also rename the fd type from i32 to RawFd to better declare the file descriptor
|
|
type.
|
|
---
|
|
core/bin/mount/setup.rs | 9 +-
|
|
libs/basic/src/fd_util.rs | 18 ++--
|
|
libs/basic/src/fs_util.rs | 28 +++---
|
|
libs/basic/src/mount_util.rs | 4 +-
|
|
8 files changed, 146 insertions(+), 107 deletions(-)
|
|
|
|
diff --git a/core/bin/mount/setup.rs b/core/bin/mount/setup.rs
|
|
index 6a13626..e7ca9df 100644
|
|
--- a/core/bin/mount/setup.rs
|
|
+++ b/core/bin/mount/setup.rs
|
|
@@ -23,6 +23,7 @@ use nix::{
|
|
sys::stat::Mode,
|
|
unistd::AccessFlags,
|
|
};
|
|
+use std::os::unix::prelude::AsRawFd;
|
|
use std::{
|
|
collections::HashMap,
|
|
fs,
|
|
@@ -361,7 +362,7 @@ impl MountPoint {
|
|
// symlink
|
|
|
|
let path = Path::new(&self.target);
|
|
- let ret = fs_util::open_parent(
|
|
+ let file = fs_util::open_parent(
|
|
path,
|
|
OFlag::O_PATH | OFlag::O_CLOEXEC,
|
|
Mode::from_bits(0).unwrap(),
|
|
@@ -369,7 +370,11 @@ impl MountPoint {
|
|
|
|
let last_file_name = path.file_name().unwrap_or_default();
|
|
|
|
- let ret = mount_util::mount_point_fd_valid(ret, last_file_name.to_str().unwrap(), flags)?;
|
|
+ let ret = mount_util::mount_point_fd_valid(
|
|
+ file.as_raw_fd(),
|
|
+ last_file_name.to_str().unwrap(),
|
|
+ flags,
|
|
+ )?;
|
|
|
|
Ok(ret)
|
|
}
|
|
diff --git a/libs/basic/src/fd_util.rs b/libs/basic/src/fd_util.rs
|
|
index 0d41966..210c830 100644
|
|
--- a/libs/basic/src/fd_util.rs
|
|
+++ b/libs/basic/src/fd_util.rs
|
|
@@ -18,6 +18,8 @@ use nix::{
|
|
ioctl_read,
|
|
sys::stat::{Mode, SFlag},
|
|
};
|
|
+use std::os::unix::prelude::FromRawFd;
|
|
+use std::{fs::File, os::unix::prelude::RawFd};
|
|
|
|
/// check if the given stat.st_mode is regular file
|
|
pub fn stat_is_reg(st_mode: u32) -> bool {
|
|
@@ -30,7 +32,7 @@ pub fn stat_is_char(st_mode: u32) -> bool {
|
|
}
|
|
|
|
///
|
|
-pub fn fd_nonblock(fd: i32, nonblock: bool) -> Result<()> {
|
|
+pub fn fd_nonblock(fd: RawFd, nonblock: bool) -> Result<()> {
|
|
assert!(fd >= 0);
|
|
|
|
let flags = nix::fcntl::fcntl(fd, FcntlArg::F_GETFL).context(NixSnafu)?;
|
|
@@ -51,7 +53,7 @@ pub fn fd_nonblock(fd: i32, nonblock: bool) -> Result<()> {
|
|
}
|
|
|
|
///
|
|
-pub fn fd_cloexec(fd: i32, cloexec: bool) -> Result<()> {
|
|
+pub fn fd_cloexec(fd: RawFd, cloexec: bool) -> Result<()> {
|
|
assert!(fd >= 0);
|
|
|
|
let flags = nix::fcntl::fcntl(fd, FcntlArg::F_GETFD).context(NixSnafu)?;
|
|
@@ -69,7 +71,7 @@ pub fn fd_cloexec(fd: i32, cloexec: bool) -> Result<()> {
|
|
}
|
|
|
|
///
|
|
-pub fn fd_is_cloexec(fd: i32) -> bool {
|
|
+pub fn fd_is_cloexec(fd: RawFd) -> bool {
|
|
assert!(fd >= 0);
|
|
|
|
let flags = nix::fcntl::fcntl(fd, FcntlArg::F_GETFD).unwrap_or(0);
|
|
@@ -78,7 +80,7 @@ pub fn fd_is_cloexec(fd: i32) -> bool {
|
|
}
|
|
|
|
///
|
|
-pub fn close(fd: i32) {
|
|
+pub fn close(fd: RawFd) {
|
|
if let Err(e) = nix::unistd::close(fd) {
|
|
log::warn!("close fd {} failed, errno: {}", fd, e);
|
|
}
|
|
@@ -90,12 +92,12 @@ pub fn close(fd: i32) {
|
|
/// this function can not work on sockets, as they can not be opened
|
|
///
|
|
/// note that this function implicitly reset the read index to zero
|
|
-pub fn fd_reopen(fd: i32, oflags: OFlag) -> Result<i32> {
|
|
+pub fn fd_reopen(fd: RawFd, oflags: OFlag) -> Result<File> {
|
|
if oflags.intersects(OFlag::O_DIRECTORY) {
|
|
let new_fd = nix::fcntl::openat(fd, ".", oflags, nix::sys::stat::Mode::empty())
|
|
.map_err(|e| Error::Nix { source: e })?;
|
|
|
|
- return Ok(new_fd);
|
|
+ return Ok(unsafe { File::from_raw_fd(new_fd) });
|
|
}
|
|
|
|
match nix::fcntl::open(
|
|
@@ -103,7 +105,7 @@ pub fn fd_reopen(fd: i32, oflags: OFlag) -> Result<i32> {
|
|
oflags,
|
|
nix::sys::stat::Mode::empty(),
|
|
) {
|
|
- Ok(n) => Ok(n),
|
|
+ Ok(n) => Ok(unsafe { File::from_raw_fd(n) }),
|
|
Err(e) => {
|
|
if e != Errno::ENOENT {
|
|
return Err(Error::Nix { source: e });
|
|
@@ -137,7 +139,7 @@ ioctl_read!(
|
|
);
|
|
|
|
/// get the diskseq according to fd
|
|
-pub fn fd_get_diskseq(fd: i32) -> Result<u64> {
|
|
+pub fn fd_get_diskseq(fd: RawFd) -> Result<u64> {
|
|
let mut diskseq: u64 = 0;
|
|
let ptr: *mut u64 = &mut diskseq;
|
|
unsafe {
|
|
diff --git a/libs/basic/src/fs_util.rs b/libs/basic/src/fs_util.rs
|
|
index 3f72658..8a8f276 100644
|
|
--- a/libs/basic/src/fs_util.rs
|
|
+++ b/libs/basic/src/fs_util.rs
|
|
@@ -22,16 +22,20 @@ use nix::{
|
|
use pathdiff::diff_paths;
|
|
use rand::Rng;
|
|
use std::{
|
|
- ffi::CString, fs::remove_dir, io::ErrorKind, os::unix::prelude::PermissionsExt, path::Path,
|
|
+ ffi::CString,
|
|
+ fs::{remove_dir, File},
|
|
+ io::ErrorKind,
|
|
+ os::unix::prelude::{AsRawFd, FromRawFd, PermissionsExt, RawFd},
|
|
+ path::Path,
|
|
};
|
|
|
|
/// open the parent directory of path
|
|
-pub fn open_parent(path: &Path, flags: OFlag, mode: Mode) -> Result<i32> {
|
|
+pub fn open_parent(path: &Path, flags: OFlag, mode: Mode) -> Result<File> {
|
|
let parent = path.parent().ok_or(Error::Nix {
|
|
source: nix::errno::Errno::EINVAL,
|
|
})?;
|
|
|
|
- nix::fcntl::open(parent, flags, mode).context(NixSnafu)
|
|
+ Ok(unsafe { File::from_raw_fd(nix::fcntl::open(parent, flags, mode).context(NixSnafu)?) })
|
|
}
|
|
|
|
/// create symlink link_name -> target
|
|
@@ -39,7 +43,7 @@ pub fn symlink(target: &str, link: &str, relative: bool) -> Result<()> {
|
|
let link_path = Path::new(&link);
|
|
let target_path = Path::new(&target);
|
|
|
|
- let (target_path, dirfd) = if relative {
|
|
+ let (target_path, dir) = if relative {
|
|
let link_path_parent = link_path.parent().ok_or(Error::NotExisted {
|
|
what: format!("{}'s parent", link_path.to_string_lossy()),
|
|
})?;
|
|
@@ -51,19 +55,19 @@ pub fn symlink(target: &str, link: &str, relative: bool) -> Result<()> {
|
|
Mode::from_bits(0).unwrap(),
|
|
)
|
|
.context(NixSnafu)?;
|
|
- (rel_path, Some(fd))
|
|
+ (rel_path, Some(unsafe { File::from_raw_fd(fd) }))
|
|
} else {
|
|
(target_path.to_path_buf(), None)
|
|
};
|
|
|
|
let mut rng = rand::thread_rng();
|
|
-
|
|
let tmp_to = format!("{}.{}", link, rng.gen::<u32>());
|
|
+ let raw_fd = dir.map(|f| f.as_raw_fd());
|
|
|
|
- nix::unistd::symlinkat(target_path.as_path(), dirfd, tmp_to.as_str()).context(NixSnafu)?;
|
|
+ nix::unistd::symlinkat(target_path.as_path(), raw_fd, tmp_to.as_str()).context(NixSnafu)?;
|
|
|
|
- if let Err(e) = renameat(dirfd, tmp_to.as_str(), dirfd, link_path) {
|
|
- let _ = unlinkat(dirfd, tmp_to.as_str(), UnlinkatFlags::NoRemoveDir);
|
|
+ if let Err(e) = renameat(raw_fd, tmp_to.as_str(), raw_fd, link_path) {
|
|
+ let _ = unlinkat(raw_fd, tmp_to.as_str(), UnlinkatFlags::NoRemoveDir);
|
|
return Err(Error::Nix { source: e });
|
|
}
|
|
|
|
@@ -71,7 +75,7 @@ pub fn symlink(target: &str, link: &str, relative: bool) -> Result<()> {
|
|
}
|
|
|
|
/// chmod based on fd opened with O_PATH
|
|
-pub fn fchmod_opath(fd: i32, mode: mode_t) -> Result<()> {
|
|
+pub fn fchmod_opath(fd: RawFd, mode: mode_t) -> Result<()> {
|
|
let fd_path = format_proc_fd_path!(fd);
|
|
|
|
let mut perms = std::fs::metadata(&fd_path).context(IoSnafu)?.permissions();
|
|
@@ -91,7 +95,7 @@ pub fn chmod(path: &str, mode: mode_t) -> Result<()> {
|
|
/// the access mode is above the old mode under old owner or the new
|
|
/// mode under new owner.
|
|
pub fn fchmod_and_chown(
|
|
- fd: i32,
|
|
+ fd: RawFd,
|
|
path: &str,
|
|
mode: Option<mode_t>,
|
|
uid: Option<Uid>,
|
|
@@ -151,7 +155,7 @@ pub fn fchmod_and_chown(
|
|
}
|
|
|
|
/// Update the timestamp of a file with fd. If 'ts' is not provided, use the current timestamp by default.
|
|
-pub fn futimens_opath(fd: i32, ts: Option<[timespec; 2]>) -> Result<()> {
|
|
+pub fn futimens_opath(fd: RawFd, ts: Option<[timespec; 2]>) -> Result<()> {
|
|
let fd_path = format_proc_fd_path!(fd);
|
|
let c_string =
|
|
CString::new(fd_path.clone()).map_err(|e| crate::Error::NulError { source: e })?;
|
|
diff --git a/libs/basic/src/mount_util.rs b/libs/basic/src/mount_util.rs
|
|
index 3b041d3..72a11d3 100644
|
|
--- a/libs/basic/src/mount_util.rs
|
|
+++ b/libs/basic/src/mount_util.rs
|
|
@@ -11,6 +11,8 @@
|
|
// See the Mulan PSL v2 for more details.
|
|
|
|
//!
|
|
+use std::os::unix::prelude::RawFd;
|
|
+
|
|
use crate::error::*;
|
|
use nix::{
|
|
fcntl::AtFlags,
|
|
@@ -18,7 +20,7 @@ use nix::{
|
|
};
|
|
|
|
///
|
|
-pub fn mount_point_fd_valid(fd: i32, file_name: &str, flags: AtFlags) -> Result<bool> {
|
|
+pub fn mount_point_fd_valid(fd: RawFd, file_name: &str, flags: AtFlags) -> Result<bool> {
|
|
assert!(fd >= 0);
|
|
|
|
let flags = if flags.contains(AtFlags::AT_SYMLINK_FOLLOW) {
|
|
--
|
|
2.33.0
|
|
|