mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 02:27:36 +03:00
OpenZFS 7336 - vfork and O_CLOEXEC causes zfs_mount EBUSY
Porting notes: - statvfs64 is replaced by statfs64. - ZFS_SUPER_MAGIC definition moved in include/sys/fs/zfs.h to share it between user and kernel space. Authored by: Prakash Surya <prakash.surya@delphix.com> Reviewed by: Matt Ahrens <mahrens@delphix.com> Reviewed by: Paul Dagnelie <pcd@delphix.com> Reviewed by: Robert Mustacchi <rm@joyent.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Ported-by: George Melikov <mail@gmelikov.ru> OpenZFS-issue: https://www.illumos.org/issues/7336 OpenZFS-commit: https://github.com/openzfs/openzfs/commit/dd862f6d Closes #5651
This commit is contained in:
committed by
Brian Behlendorf
parent
f925de3a20
commit
774ee3c7ce
@@ -75,6 +75,7 @@
|
||||
#include <sys/mntent.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/vfs.h>
|
||||
|
||||
#include <libzfs.h>
|
||||
|
||||
@@ -170,13 +171,32 @@ is_shared(libzfs_handle_t *hdl, const char *mountpoint, zfs_share_proto_t proto)
|
||||
return (SHARED_NOT_SHARED);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if the specified directory is empty. If we can't open the
|
||||
* directory at all, return true so that the mount can fail with a more
|
||||
* informative error message.
|
||||
*/
|
||||
static boolean_t
|
||||
dir_is_empty(const char *dirname)
|
||||
dir_is_empty_stat(const char *dirname)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
/*
|
||||
* We only want to return false if the given path is a non empty
|
||||
* directory, all other errors are handled elsewhere.
|
||||
*/
|
||||
if (stat(dirname, &st) < 0 || !S_ISDIR(st.st_mode)) {
|
||||
return (B_TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* An empty directory will still have two entries in it, one
|
||||
* entry for each of "." and "..".
|
||||
*/
|
||||
if (st.st_size > 2) {
|
||||
return (B_FALSE);
|
||||
}
|
||||
|
||||
return (B_TRUE);
|
||||
}
|
||||
|
||||
static boolean_t
|
||||
dir_is_empty_readdir(const char *dirname)
|
||||
{
|
||||
DIR *dirp;
|
||||
struct dirent64 *dp;
|
||||
@@ -205,6 +225,42 @@ dir_is_empty(const char *dirname)
|
||||
return (B_TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if the specified directory is empty. If we can't open the
|
||||
* directory at all, return true so that the mount can fail with a more
|
||||
* informative error message.
|
||||
*/
|
||||
static boolean_t
|
||||
dir_is_empty(const char *dirname)
|
||||
{
|
||||
struct statfs64 st;
|
||||
|
||||
/*
|
||||
* If the statvfs call fails or the filesystem is not a ZFS
|
||||
* filesystem, fall back to the slow path which uses readdir.
|
||||
*/
|
||||
if ((statfs64(dirname, &st) != 0) ||
|
||||
(st.f_type != ZFS_SUPER_MAGIC)) {
|
||||
return (dir_is_empty_readdir(dirname));
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point, we know the provided path is on a ZFS
|
||||
* filesystem, so we can use stat instead of readdir to
|
||||
* determine if the directory is empty or not. We try to avoid
|
||||
* using readdir because that requires opening "dirname"; this
|
||||
* open file descriptor can potentially end up in a child
|
||||
* process if there's a concurrent fork, thus preventing the
|
||||
* zfs_mount() from otherwise succeeding (the open file
|
||||
* descriptor inherited by the child process will cause the
|
||||
* parent's mount to fail with EBUSY). The performance
|
||||
* implications of replacing the open, read, and close with a
|
||||
* single stat is nice; but is not the main motivation for the
|
||||
* added complexity.
|
||||
*/
|
||||
return (dir_is_empty_stat(dirname));
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks to see if the mount is active. If the filesystem is mounted, we fill
|
||||
* in 'where' with the current mountpoint, and return 1. Otherwise, we return
|
||||
|
||||
Reference in New Issue
Block a user