diff mbox

[3/7] libjunction: Introduce new APIs for creating and deleting FedFS junctions

Message ID 20120104210638.8810.73629.stgit@degas.1015granger.net
State Accepted
Headers show

Commit Message

Chuck Lever Jan. 4, 2012, 9:06 p.m. UTC
Introduce fresh APIs that encapsulate the activities of managing the
junction data and the junction object's mode bits.

The common junction utility functions should no longer be invoked
outside of libjunction.  Instead, upper layers should invoke the
type-specific APIs we're introducing in this patch.  We're headed
towards a world where callers like rpc.fedfsd will not care about the
mode bit settings or what extended attributes are used to represent
junctions.

Note that fedfs_add_junction() behaves a little differently than the
previous code.  It updates the mode bits _after_ it has successfully
created the mode xattr.  This should prevent the kernel from
generating an upcall on a junction that is partially formed.

And, fedfs_add_junction() is more careful to clean up if something
fails.

This patch also addresses an open file descriptor leak in
fedfs_save_mode().

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---

 src/fedfsd/svc.c           |   14 +-----
 src/include/junction.h     |    7 +--
 src/libjunction/junction.c |  108 ++++++++++++++++++++++++++++++++++++--------
 3 files changed, 93 insertions(+), 36 deletions(-)
diff mbox

Patch

diff --git a/src/fedfsd/svc.c b/src/fedfsd/svc.c
index 6d548c1..ece0702 100644
--- a/src/fedfsd/svc.c
+++ b/src/fedfsd/svc.c
@@ -531,13 +531,7 @@  fedfsd_svc_create_junction_1(SVCXPRT *xprt)
 		goto out;
 	}
 
-	result = fedfs_save_mode(pathname);
-	if (result != FEDFS_OK) {
-		xlog(D_GENERAL, "%s: fedfs_save_mode", __func__);
-		goto out;
-	}
-
-	result = fedfs_store_fsn(pathname, fsn_uuid, host);
+	result = fedfs_add_junction(pathname, fsn_uuid, host);
 	if (result != FEDFS_OK) {
 		xlog(D_GENERAL, "%s: fedfs_store_fsn", __func__);
 		goto out;
@@ -635,11 +629,7 @@  fedfsd_svc_delete_junction_1(SVCXPRT *xprt)
 		goto out;
 	}
 
-	result = fedfs_restore_mode(pathname);
-	if (result != FEDFS_OK)
-		goto out;
-
-	result = fedfs_remove_fsn(pathname);
+	result = fedfs_delete_junction(pathname);
 	if (result!= FEDFS_OK)
 		goto out;
 
diff --git a/src/include/junction.h b/src/include/junction.h
index edbab7b..de2f496 100644
--- a/src/include/junction.h
+++ b/src/include/junction.h
@@ -28,17 +28,14 @@ 
 
 #include "nsdb.h"
 
-FedFsStatus	 fedfs_remove_fsn(const char *pathname);
-FedFsStatus	 fedfs_store_fsn(const char *pathname, const char *uuid,
+FedFsStatus	 fedfs_delete_junction(const char *pathname);
+FedFsStatus	 fedfs_add_junction(const char *pathname, const char *uuid,
 				const nsdb_t host);
 FedFsStatus	 fedfs_get_fsn(const char *pathname, char **uuid,
 				nsdb_t *host);
 FedFsStatus	 fedfs_is_prejunction(const char *pathname);
 FedFsStatus	 fedfs_is_junction(const char *pathname);
 
-FedFsStatus	 fedfs_save_mode(const char *pathname);
-FedFsStatus	 fedfs_restore_mode(const char *pathname);
-
 FedFsStatus	 junction_flush_exports_cache(void);
 
 #endif	/* !_FEDFS_JUNCTION_H_ */
diff --git a/src/libjunction/junction.c b/src/libjunction/junction.c
index 10fc5f2..472f4ef 100644
--- a/src/libjunction/junction.c
+++ b/src/libjunction/junction.c
@@ -360,7 +360,7 @@  fedfs_remove_xattr(int fd, const char *pathname, const char *name)
  *
  * @note Access to trusted attributes requires CAP_SYS_ADMIN.
  */
-FedFsStatus
+static FedFsStatus
 fedfs_remove_fsn(const char *pathname)
 {
 	FedFsStatus retval;
@@ -394,16 +394,13 @@  out:
  * @param host an initialized nsdb_t object
  * @return a FedFsStatus code
  */
-FedFsStatus
+static FedFsStatus
 fedfs_store_fsn(const char *pathname, const char *fsn_uuid, const nsdb_t host)
 {
 	FedFsStatus retval;
 	char buf[20];
 	int fd, len;
 
-	if (fsn_uuid == NULL || host == NULL)
-		return FEDFS_ERR_INVAL;
-
 	retval = fedfs_open_path(pathname, &fd);
 	if (retval != FEDFS_OK)
 		return retval;
@@ -411,32 +408,24 @@  fedfs_store_fsn(const char *pathname, const char *fsn_uuid, const nsdb_t host)
 	retval = fedfs_set_xattr(fd, pathname, FEDFSD_XATTR_NAME_TYPE,
 			FEDFSD_XATTR_NAME_TYPE, sizeof(FEDFSD_XATTR_NAME_TYPE));
 	if (retval != FEDFS_OK)
-		goto out_err;
+		goto out;
 
 	retval = fedfs_set_xattr(fd, pathname, FEDFSD_XATTR_NAME_FSNUUID,
 			fsn_uuid, strlen(fsn_uuid) + 1);
 	if (retval != FEDFS_OK)
-		goto out_err;
+		goto out;
 
 	retval = fedfs_set_xattr(fd, pathname, FEDFSD_XATTR_NAME_NSDB,
 			nsdb_hostname(host), nsdb_hostname_len(host) + 1);
 	if (retval != FEDFS_OK)
-		goto out_err;
+		goto out;
 
 	len = snprintf(buf, sizeof(buf), "%u", nsdb_port(host));
 	retval = fedfs_set_xattr(fd, pathname, FEDFSD_XATTR_NAME_PORT, buf, len + 1);
-	if (retval != FEDFS_OK)
-		goto out_err;
-
-	retval = fedfs_set_sticky_bit(fd, pathname);
 
 out:
 	(void)close(fd);
 	return retval;
-
-out_err:
-	(void)fedfs_remove_fsn(pathname);
-	goto out;
 }
 
 /**
@@ -645,6 +634,7 @@  FedFsStatus
 fedfs_save_mode(const char *pathname)
 {
 	FedFsStatus retval;
+	unsigned int mode;
 	struct stat stb;
 	char buf[16];
 	int fd;
@@ -659,10 +649,26 @@  fedfs_save_mode(const char *pathname)
 		return FEDFS_ERR_ACCESS;
 	}
 
-	(void)snprintf(buf, sizeof(buf), "%o", ALLPERMS & stb.st_mode);
-
-	return fedfs_set_xattr(fd, pathname, FEDFSD_XATTR_NAME_MODE,
+	mode = ALLPERMS & stb.st_mode;
+	(void)snprintf(buf, sizeof(buf), "%o", mode);
+	retval = fedfs_set_xattr(fd, pathname, FEDFSD_XATTR_NAME_MODE,
 				buf, strlen(buf));
+	if (retval != FEDFS_OK)
+		goto out;
+
+	retval = fedfs_set_sticky_bit(fd, pathname);
+	if (retval != FEDFS_OK) {
+		(void)fedfs_remove_xattr(fd, pathname,
+						FEDFSD_XATTR_NAME_MODE);
+		goto out;
+	}
+
+	xlog(D_CALL, "%s: saved mode %o to %s", __func__, mode, pathname);
+	retval = FEDFS_OK;
+
+out:
+	(void)close(fd);
+	return retval;
 }
 
 /**
@@ -702,6 +708,7 @@  fedfs_restore_mode(const char *pathname)
 		goto out;
 	}
 
+	xlog(D_CALL, "%s: restored mode %o to %s", __func__, mode, pathname);
 	retval = FEDFS_OK;
 
 out:
@@ -709,3 +716,66 @@  out:
 	(void)close(fd);
 	return retval;
 }
+
+/**
+ * Add FedFS junction information to a pre-existing object
+ *
+ * @param pathname NUL-terminated C string containing pathname of a junction
+ * @param fsn_uuid NUL-terminated C string containing FSN UUID to store
+ * @param host an initialized nsdb_t object
+ * @return a FedFsStatus code
+ *
+ * An error occurs if the object referred to by "pathname" does not
+ * exist or contains existing FedFS junction data.
+ */
+FedFsStatus
+fedfs_add_junction(const char *pathname, const char *fsn_uuid, const nsdb_t host)
+{
+	FedFsStatus retval;
+
+	if (fsn_uuid == NULL || host == NULL)
+		return FEDFS_ERR_INVAL;
+
+	retval = fedfs_is_prejunction(pathname);
+	if (retval != FEDFS_ERR_NOTJUNCT)
+		return retval;
+
+	retval = fedfs_store_fsn(pathname, fsn_uuid, host);
+	if (retval != FEDFS_OK)
+		goto out_err;
+
+	retval = fedfs_save_mode(pathname);
+	if (retval != FEDFS_OK)
+		goto out_err;
+
+	return retval;
+
+out_err:
+	(void)fedfs_remove_fsn(pathname);
+	return retval;
+}
+
+/**
+ * Remove FedFS junction information from an object
+ *
+ * @param pathname NUL-terminated C string containing pathname of a directory
+ * @return a FedFsStatus code
+ *
+ * An error occurs if the object referred to by "pathname" does not
+ * exist or does not contain FedFS junction data.
+ */
+FedFsStatus
+fedfs_delete_junction(const char *pathname)
+{
+	FedFsStatus retval;
+
+	retval = fedfs_is_junction(pathname);
+	if (retval != FEDFS_OK)
+		return retval;
+
+	retval = fedfs_restore_mode(pathname);
+	if (retval != FEDFS_OK)
+		return retval;
+
+	return fedfs_remove_fsn(pathname);
+}