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 " \ " 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 " \ " 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); /*