summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmd/mount_zfs/mount_zfs.c2
-rw-r--r--lib/libspl/include/sys/mntent.h1
-rw-r--r--lib/libzfs/libzfs_mount.c2
-rw-r--r--module/zfs/zfs_ctldir.c14
4 files changed, 15 insertions, 4 deletions
diff --git a/cmd/mount_zfs/mount_zfs.c b/cmd/mount_zfs/mount_zfs.c
index 4db33ed69..83b57f4e9 100644
--- a/cmd/mount_zfs/mount_zfs.c
+++ b/cmd/mount_zfs/mount_zfs.c
@@ -528,7 +528,7 @@ main(int argc, char **argv)
case EBUSY:
(void) fprintf(stderr, gettext("filesystem "
"'%s' is already mounted\n"), dataset);
- return (MOUNT_SYSERR);
+ return (MOUNT_BUSY);
default:
(void) fprintf(stderr, gettext("filesystem "
"'%s' can not be mounted due to error "
diff --git a/lib/libspl/include/sys/mntent.h b/lib/libspl/include/sys/mntent.h
index 8fad65b56..736c3f866 100644
--- a/lib/libspl/include/sys/mntent.h
+++ b/lib/libspl/include/sys/mntent.h
@@ -39,6 +39,7 @@
#define MOUNT_FILEIO 0x10 /* Error updating/locking /etc/mtab */
#define MOUNT_FAIL 0x20 /* Mount failed */
#define MOUNT_SOMEOK 0x40 /* At least on mount succeeded */
+#define MOUNT_BUSY 0x80 /* Mount failed due to EBUSY */
#define MNTOPT_ASYNC "async" /* all I/O is asynchronous */
#define MNTOPT_ATIME "atime" /* update atime for files */
diff --git a/lib/libzfs/libzfs_mount.c b/lib/libzfs/libzfs_mount.c
index bded1f001..68e4ef4de 100644
--- a/lib/libzfs/libzfs_mount.c
+++ b/lib/libzfs/libzfs_mount.c
@@ -292,6 +292,8 @@ do_mount(const char *src, const char *mntpt, char *opts)
return EINTR;
if (rc & MOUNT_SOFTWARE)
return EPIPE;
+ if (rc & MOUNT_BUSY)
+ return EBUSY;
if (rc & MOUNT_SYSERR)
return EAGAIN;
if (rc & MOUNT_USAGE)
diff --git a/module/zfs/zfs_ctldir.c b/module/zfs/zfs_ctldir.c
index c08e9dd9b..5bea0b6c9 100644
--- a/module/zfs/zfs_ctldir.c
+++ b/module/zfs/zfs_ctldir.c
@@ -692,7 +692,7 @@ zfsctl_snapdir_inactive(struct inode *ip)
* best effort. In the case where it does fail, perhaps because
* it's in use, the unmount will fail harmlessly.
*/
-#define SET_UNMOUNT_CMD \
+#define SET_UNMOUNT_CMD \
"exec 0</dev/null " \
" 1>/dev/null " \
" 2>/dev/null; " \
@@ -801,7 +801,9 @@ zfsctl_unmount_snapshots(zfs_sb_t *zsb, int flags, int *count)
return ((*count > 0) ? EEXIST : 0);
}
-#define SET_MOUNT_CMD \
+#define MOUNT_BUSY 0x80 /* Mount failed due to EBUSY (from mntent.h) */
+
+#define SET_MOUNT_CMD \
"exec 0</dev/null " \
" 1>/dev/null " \
" 2>/dev/null; " \
@@ -839,17 +841,23 @@ zfsctl_mount_snapshot(struct path *path, int flags)
* function is marked GPL-only and cannot be used. On error we
* careful to log the real error to the console and return EISDIR
* to safely abort the automount. This should be very rare.
+ *
+ * If the user mode helper happens to return EBUSY, a concurrent
+ * mount is already in progress in which case the error is ignored.
+ * Take note that if the program was executed successfully the return
+ * value from call_usermodehelper() will be (exitcode << 8 + signal).
*/
argv[2] = kmem_asprintf(SET_MOUNT_CMD, full_name, full_path);
error = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
strfree(argv[2]);
- if (error) {
+ if (error && !(error & MOUNT_BUSY << 8)) {
printk("ZFS: Unable to automount %s at %s: %d\n",
full_name, full_path, error);
error = SET_ERROR(EISDIR);
goto error;
}
+ error = 0;
mutex_enter(&zsb->z_ctldir_lock);
/*