[PATCH 03/12] Share Handling

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



03/12 - shares_support

Provides functions to set/get shares of a specific resource of a resource
group.
Defines a teardown function that is intended to be called when user
disables resource group (by umount of the configfs component).
--

Signed-Off-By: Chandra Seetharaman <[email protected]>
Signed-Off-By: Hubertus Franke <[email protected]>
Signed-Off-By: Shailabh Nagar <[email protected]>
Signed-Off-By: Gerrit Huizenga <[email protected]>
Signed-off-by: MAEDA Naoaki <[email protected]>
Signed-Off-By: Matt Helsley <[email protected]>

 include/linux/res_group.h    |   14 ++
 include/linux/res_group_rc.h |   10 +
 kernel/res_group/Makefile    |    2 
 kernel/res_group/local.h     |    6 +
 kernel/res_group/res_group.c |   24 ++++
 kernel/res_group/shares.c    |  242 +++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 297 insertions(+), 1 deletion(-)

Index: linux-2617-rc3/include/linux/res_group.h
===================================================================
--- linux-2617-rc3.orig/include/linux/res_group.h	2006-04-27 09:22:04.000000000 -0700
+++ linux-2617-rc3/include/linux/res_group.h	2006-04-27 09:22:07.000000000 -0700
@@ -54,6 +54,20 @@
  * resource group need to be locked.
 */
 struct res_shares {
+	/* shares only set by userspace */
+	int min_shares; /* minimun fraction of parent's resources allowed */
+	int max_shares; /* maximum fraction of parent's resources allowed */
+	int child_shares_divisor; /* >= 1, may not be DONT_CARE */
+
+	/*
+	 * share values invisible to userspace.  adjusted when userspace
+	 * sets shares
+	 */
+	int unused_min_shares;
+		/* 0 <= unused_min_shares <= (child_shares_divisor -
+		 * 			Sum of min_shares of children)
+		 */
+	int cur_max_shares; /* max(children's max_shares). need better name */
 };
 
 /*
Index: linux-2617-rc3/kernel/res_group/shares.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2617-rc3/kernel/res_group/shares.c	2006-04-27 09:22:07.000000000 -0700
@@ -0,0 +1,242 @@
+/*
+ * shares.c - Share management functions for Resource Groups
+ *
+ * Copyright (C) Chandra Seetharaman,  IBM Corp. 2003, 2004, 2005, 2006
+ *		(C) Hubertus Franke,  IBM Corp. 2004
+ *		(C) Matt Helsley,  IBM Corp. 2006
+ *
+ * Latest version, more details at http://ckrm.sf.net
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/errno.h>
+#include <linux/res_group_rc.h>
+
+/*
+ * Share values can be quantitative (quantity of memory for instance) or
+ * symbolic. The symbolic value DONT_CARE allows for any quantity of a resource
+ * to be substituted in its place. The symbolic value UNCHANGED is only used
+ * when setting share values and means that the old value should be used.
+ */
+
+/* Is the share a quantity (as opposed to "symbols" DONT_CARE or UNCHANGED) */
+static inline int is_share_quantitative(int share)
+{
+	return (share >= 0);
+}
+
+static inline int is_share_symbolic(int share)
+{
+	return !is_share_quantitative(share);
+}
+
+static inline int is_share_valid(int share)
+{
+	return ((share == SHARE_DONT_CARE) ||
+			(share == SHARE_UNSUPPORTED) ||
+			is_share_quantitative(share));
+}
+
+static inline int did_share_change(int share)
+{
+	return (share != SHARE_UNCHANGED);
+}
+
+static inline int change_supported(int share)
+{
+	return (share != SHARE_UNSUPPORTED);
+}
+
+/*
+ * Caller is responsible for protecting 'parent'
+ * Caller is responsible for making sure that the sum of sibling min_shares
+ * doesn't exceed parent's total min_shares.
+ */
+static inline void child_min_shares_changed(struct res_shares *parent,
+				   int child_cur_min_shares,
+				   int child_new_min_shares)
+{
+	if (is_share_quantitative(child_new_min_shares))
+		parent->unused_min_shares -= child_new_min_shares;
+	if (is_share_quantitative(child_cur_min_shares))
+		parent->unused_min_shares += child_cur_min_shares;
+}
+
+/*
+ * Set parent's cur_max_shares to the largest 'max_shares' of all
+ * of its children.
+ */
+static inline void set_cur_max_shares(struct resource_group *parent,
+					struct res_controller *ctlr)
+{
+	int max_shares = 0;
+	struct resource_group *child = NULL;
+	struct res_shares *child_shares, *parent_shares;
+
+	for_each_child(child, parent) {
+		child_shares = get_controller_shares(child, ctlr);
+		max_shares = max(max_shares, child_shares->max_shares);
+	}
+
+	parent_shares = get_controller_shares(parent, ctlr);
+	parent_shares->cur_max_shares = max_shares;
+}
+
+/*
+ * Return -EINVAL if the child's shares violate self-consistency or
+ * parent-imposed restrictions. Otherwise return 0.
+ *
+ * This involves checking shares between the child and its parent;
+ * the child and itself (userspace can't be trusted).
+ */
+static inline int are_shares_valid(struct res_shares *child,
+				   struct res_shares *parent,
+				   int current_usage,
+				   int min_shares_increase)
+{
+	/*
+	 * CHILD <-> PARENT validation
+	 * Increases in child's min_shares or max_shares can't exceed
+	 * limitations imposed by the parent resource group.
+	 * Only validate this if we have a parent.
+	 */
+	if (parent &&
+	    ((is_share_quantitative(child->min_shares) &&
+	      (min_shares_increase > parent->unused_min_shares)) ||
+	     (is_share_quantitative(child->max_shares) &&
+	      (child->max_shares > parent->child_shares_divisor))))
+		return -EINVAL;
+
+	/* CHILD validation: is min valid */
+	if (!is_share_valid(child->min_shares))
+		return -EINVAL;
+
+	/* CHILD validation: is max valid */
+	if (!is_share_valid(child->max_shares))
+		return -EINVAL;
+
+	/*
+	 * CHILD validation: is divisor quantitative & current_usage
+	 * is not more than the new divisor
+	 */
+	if (!is_share_quantitative(child->child_shares_divisor) ||
+			(current_usage > child->child_shares_divisor))
+		return -EINVAL;
+
+	/*
+	 * CHILD validation: is the new child_shares_divisor large
+	 * enough to accomodate largest max_shares of any of my child
+	 */
+	if (child->child_shares_divisor < child->cur_max_shares)
+		return -EINVAL;
+
+	/* CHILD validation: min <= max */
+	if (is_share_quantitative(child->min_shares) &&
+			is_share_quantitative(child->max_shares) &&
+			(child->min_shares > child->max_shares))
+		return -EINVAL;
+
+	return 0;
+}
+
+/*
+ * Set the resource shares of a child resource group given the new shares
+ * specified by userspace, the child's current shares, and the parent
+ * resource group's shares.
+ *
+ * Caller is responsible for holding group_lock of child and parent
+ * resource groups to protect the shares structures passed to this function.
+ */
+static int set_shares(const struct res_shares *new,
+		    struct res_shares *child_shares,
+    		    struct res_shares *parent_shares)
+{
+	int rc, current_usage, min_shares_increase;
+	struct res_shares final_shares;
+
+	BUG_ON(!new || !child_shares);
+
+	final_shares = *child_shares;
+	if (did_share_change(new->child_shares_divisor) &&
+			change_supported(child_shares->child_shares_divisor))
+		final_shares.child_shares_divisor = new->child_shares_divisor;
+	if (did_share_change(new->min_shares) &&
+			change_supported(child_shares->min_shares))
+		final_shares.min_shares = new->min_shares;
+	if (did_share_change(new->max_shares) &&
+			change_supported(child_shares->max_shares))
+		final_shares.max_shares = new->max_shares;
+
+	current_usage = child_shares->child_shares_divisor -
+	    		 child_shares->unused_min_shares;
+	min_shares_increase = final_shares.min_shares;
+	if (is_share_quantitative(child_shares->min_shares))
+		min_shares_increase -= child_shares->min_shares;
+
+	rc = are_shares_valid(&final_shares, parent_shares, current_usage,
+   			      min_shares_increase);
+	if (rc)
+		return rc; /* new shares would violate restrictions */
+
+	if (did_share_change(new->child_shares_divisor))
+		final_shares.unused_min_shares =
+			(final_shares.child_shares_divisor - current_usage);
+	*child_shares = final_shares;
+	return 0;
+}
+
+int set_controller_shares(struct resource_group *rgroup,
+					struct res_controller *ctlr,
+					const struct res_shares *new_shares)
+{
+	struct res_shares *shares, *parent_shares;
+	int prev_min, prev_max, rc;
+
+	if (!ctlr->shares_changed)
+		return -EINVAL;
+
+	shares = get_controller_shares(rgroup, ctlr);
+	if (!shares)
+		return -EINVAL;
+
+	prev_min = shares->min_shares;
+	prev_max = shares->max_shares;
+
+	if (!is_res_group_root(rgroup))
+		spin_lock(&rgroup->parent->group_lock);
+	spin_lock(&rgroup->group_lock);
+	parent_shares = get_controller_shares(rgroup->parent, ctlr);
+	rc = set_shares(new_shares, shares, parent_shares);
+	spin_unlock(&rgroup->group_lock);
+
+	if (rc || is_res_group_root(rgroup))
+		goto done;
+
+	/* Notify parent about changes in my shares */
+	child_min_shares_changed(parent_shares, prev_min,
+				      shares->min_shares);
+	if (prev_max != shares->max_shares)
+		set_cur_max_shares(rgroup->parent, ctlr);
+
+done:
+	if (!is_res_group_root(rgroup))
+		spin_unlock(&rgroup->parent->group_lock);
+	if (!rc)
+		ctlr->shares_changed(shares);
+	return rc;
+}
+
+void set_shares_to_default(struct resource_group *rgroup,
+						struct res_controller *ctlr)
+{
+	struct res_shares shares = {
+		.min_shares = SHARE_DONT_CARE,
+		.max_shares = SHARE_DONT_CARE,
+		.child_shares_divisor = SHARE_DEFAULT_DIVISOR,
+	};
+	set_controller_shares(rgroup, ctlr, &shares);
+}
+
Index: linux-2617-rc3/kernel/res_group/Makefile
===================================================================
--- linux-2617-rc3.orig/kernel/res_group/Makefile	2006-04-27 09:21:42.000000000 -0700
+++ linux-2617-rc3/kernel/res_group/Makefile	2006-04-27 09:22:07.000000000 -0700
@@ -1 +1 @@
-obj-y = res_group.o
+obj-y = res_group.o shares.o
Index: linux-2617-rc3/kernel/res_group/res_group.c
===================================================================
--- linux-2617-rc3.orig/kernel/res_group/res_group.c	2006-04-27 09:22:04.000000000 -0700
+++ linux-2617-rc3/kernel/res_group/res_group.c	2006-04-27 09:22:07.000000000 -0700
@@ -173,6 +173,8 @@ static void do_free_shares_struct(struct
 	if (shares == NULL)
 		return;
 
+	set_shares_to_default(rgroup, ctlr);
+
 	spin_lock(&rgroup->group_lock);
 	rgroup->shares[ctlr->ctlr_id] = NULL;
 	spin_unlock(&rgroup->group_lock);
@@ -345,6 +347,26 @@ int unregister_controller(struct res_con
 	return remove_controller(ctlr);
 }
 
+/*
+ * Bring the state of Resource Groups to the initial state. Only shares
+ * of the default resource group need to be changed to default values.
+ * At this point no user-defined resource groups should exist.
+ */
+void res_group_teardown(void)
+{
+	int i;
+	struct res_controller *ctlr;
+
+	BUG_ON(num_res_groups != 0);
+	for (i = 0; i < MAX_RES_CTLRS; i++) {
+		ctlr = get_controller_by_id(i);
+		if (ctlr) {
+			set_shares_to_default(&default_res_group, ctlr);
+			put_controller(ctlr);
+		}
+	}
+}
+
 EXPORT_SYMBOL_GPL(register_controller);
 EXPORT_SYMBOL_GPL(unregister_controller);
 EXPORT_SYMBOL_GPL(get_controller_by_name);
@@ -353,3 +375,5 @@ EXPORT_SYMBOL_GPL(put_controller);
 EXPORT_SYMBOL_GPL(alloc_res_group);
 EXPORT_SYMBOL_GPL(free_res_group);
 EXPORT_SYMBOL_GPL(default_res_group);
+EXPORT_SYMBOL_GPL(set_controller_shares);
+EXPORT_SYMBOL_GPL(res_group_teardown);
Index: linux-2617-rc3/include/linux/res_group_rc.h
===================================================================
--- linux-2617-rc3.orig/include/linux/res_group_rc.h	2006-04-27 09:22:04.000000000 -0700
+++ linux-2617-rc3/include/linux/res_group_rc.h	2006-04-27 09:22:07.000000000 -0700
@@ -74,4 +74,14 @@ static inline int is_res_group_root(cons
 #define for_each_child(child, parent)	\
 	list_for_each_entry(child, &parent->children, siblings)
 
+/* Get controller specific shares structure for the given resource group */
+static inline struct res_shares *get_controller_shares(
+		struct resource_group *rgroup, struct res_controller *ctlr)
+{
+	if (rgroup && ctlr)
+		return rgroup->shares[ctlr->ctlr_id];
+	else
+		return NO_SHARE;
+}
+
 #endif /* _LINUX_RES_GROUP_RC_H */
Index: linux-2617-rc3/kernel/res_group/local.h
===================================================================
--- linux-2617-rc3.orig/kernel/res_group/local.h	2006-04-27 09:22:04.000000000 -0700
+++ linux-2617-rc3/kernel/res_group/local.h	2006-04-27 09:22:07.000000000 -0700
@@ -12,3 +12,9 @@ extern struct resource_group *alloc_res_
 							const char *);
 extern int free_res_group(struct resource_group *);
 extern void release_res_group(struct kref *);
+extern int set_controller_shares(struct resource_group *,
+			struct res_controller *, const struct res_shares *);
+/* Set shares for the given resource group and resource to default values */
+extern void set_shares_to_default(struct resource_group *,
+						struct res_controller *);
+extern void res_group_teardown(void);

-- 

----------------------------------------------------------------------
    Chandra Seetharaman               | Be careful what you choose....
              - [email protected]   |      .......you may get it.
----------------------------------------------------------------------
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux