From 27ccd4147bd29e9334c57a08d99481447a19c82f Mon Sep 17 00:00:00 2001
From: Cyril Plisko <cyril.plisko@mountall.com>
Date: Wed, 5 Sep 2012 19:44:53 +0300
Subject: [PATCH] Avoid running exportfs on each zfs/zpool command invocation

Delay executing exportfs command until its results are actually
required.

Signed-off-by: Cyril Plisko <cyril.plisko@mountall.com>
Signed-off-by: Gunnar Beutner <gunnar@beutner.name>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
---
 lib/libshare/nfs.c | 39 ++++++++++++++++++++++++++++++---------
 1 file changed, 30 insertions(+), 9 deletions(-)

diff --git a/lib/libshare/nfs.c b/lib/libshare/nfs.c
index 56725d27c3..53691ebe58 100644
--- a/lib/libshare/nfs.c
+++ b/lib/libshare/nfs.c
@@ -22,6 +22,7 @@
 /*
  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2011 Gunnar Beutner
+ * Copyright (c) 2012 Cyril Plisko. All rights reserved.
  */
 
 #include <stdio.h>
@@ -33,8 +34,9 @@
 #include <libshare.h>
 #include "libshare_impl.h"
 
+static boolean_t nfs_available(void);
+
 static sa_fstype_t *nfs_fstype;
-static boolean_t nfs_available;
 
 /*
  * nfs_exportfs_temp_fd refers to a temporary copy of the output
@@ -407,7 +409,7 @@ nfs_enable_share(sa_share_impl_t impl_share)
 	char *shareopts, *linux_opts;
 	int rc;
 
-	if (!nfs_available) {
+	if (!nfs_available()) {
 		return SA_SYSTEM_ERR;
 	}
 
@@ -480,7 +482,7 @@ nfs_disable_share_one(const char *sharepath, const char *host,
 static int
 nfs_disable_share(sa_share_impl_t impl_share)
 {
-	if (!nfs_available) {
+	if (!nfs_available()) {
 		/*
 		 * The share can't possibly be active, so nothing
 		 * needs to be done to disable it.
@@ -520,7 +522,7 @@ is_share_active(sa_share_impl_t impl_share)
 	char *tab, *cur;
 	FILE *nfs_exportfs_temp_fp;
 
-	if (nfs_exportfs_temp_fd < 0)
+	if (!nfs_available())
 		return B_FALSE;
 
 	nfs_exportfs_temp_fp = fdopen(dup(nfs_exportfs_temp_fd), "r");
@@ -671,18 +673,27 @@ nfs_check_exportfs(void)
 
 	pid = fork();
 
-	if (pid < 0)
+	if (pid < 0) {
+		(void) close(nfs_exportfs_temp_fd);
+		nfs_exportfs_temp_fd = -1;
 		return SA_SYSTEM_ERR;
+	}
 
 	if (pid > 0) {
 		while ((rc = waitpid(pid, &status, 0)) <= 0 && errno == EINTR)
 			; /* empty loop body */
 
-		if (rc <= 0)
+		if (rc <= 0) {
+			(void) close(nfs_exportfs_temp_fd);
+			nfs_exportfs_temp_fd = -1;
 			return SA_SYSTEM_ERR;
+		}
 
-		if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+		if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+			(void) close(nfs_exportfs_temp_fd);
+			nfs_exportfs_temp_fd = -1;
 			return SA_CONFIG_ERR;
+		}
 
 		return SA_OK;
 	}
@@ -703,13 +714,23 @@ nfs_check_exportfs(void)
 	exit(0);
 }
 
+/*
+ * Provides a convenient wrapper for determing nfs availability
+ */
+static boolean_t
+nfs_available(void)
+{
+	if (nfs_exportfs_temp_fd == -1)
+		(void) nfs_check_exportfs();
+
+	return (nfs_exportfs_temp_fd != -1) ? B_TRUE : B_FALSE;
+}
+
 /**
  * Initializes the NFS functionality of libshare.
  */
 void
 libshare_nfs_init(void)
 {
-	nfs_available = (nfs_check_exportfs() == SA_OK);
-
 	nfs_fstype = register_fstype("nfs", &nfs_shareops);
 }