]> granicus.if.org Git - zfs/commitdiff
Handle concurrent snapshot automounts failing due to EBUSY.
authorTim Chase <tim@chase2k.com>
Thu, 7 Nov 2013 05:55:18 +0000 (23:55 -0600)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Fri, 8 Nov 2013 18:45:14 +0000 (10:45 -0800)
In the current snapshot automount implementation, it is possible for
multiple mounts to attempted concurrently.  Only one of the mounts will
succeed and the other will fail.  The failed mounts will cause an EREMOTE
to be propagated back to the application.

This commit works around the problem by adding a new exit status,
MOUNT_BUSY to the mount.zfs program which is used when the underlying
mount(2) call returns EBUSY.  The zfs code detects this condition and
treats it as if the mount had succeeded.

Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #1819

cmd/mount_zfs/mount_zfs.c
lib/libspl/include/sys/mntent.h
lib/libzfs/libzfs_mount.c
module/zfs/zfs_ctldir.c

index 4db33ed691fe612b133c2635733c72249c253716..83b57f4e913f09f2194baefb12530c7dad86126f 100644 (file)
@@ -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 "
index 8fad65b56f86a3affe605fa6cf27d7a3bdfba4ff..736c3f866ddf1993fec81f7f024c5040c168a657 100644 (file)
@@ -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 */
index bded1f001425b8bf77979911b0dcfecdc52eca0f..68e4ef4de5993c999e0539eb9e3acb2a43ce3945 100644 (file)
@@ -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)
index c08e9dd9b959cd1433df85b63e640ef5f1380a48..5bea0b6c94f576b80cc2468f806b40dd9265f2a2 100644 (file)
@@ -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);
 
        /*