[patch 25/38] CKRM e18: Add fork rate control to the numtasks controller

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

 



Add fork rate control to the numtasks controller.

Signed-Off-By: Matt Helsley <[email protected]>
Signed-Off-By: Gerrit Huizenga <[email protected]>

---------------------------------------------------------------------

Index: linux-2.6.12-ckrm1/Documentation/ckrm/numtasks
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.12-ckrm1/Documentation/ckrm/numtasks	2005-06-20 15:04:51.000000000 -0700
@@ -0,0 +1,122 @@
+Introduction
+-------------
+
+Numtasks is a resource controller under the CKRM framework that allows the
+user/sysadmin to manage the number of tasks a class can create. It also allows
+one to limit the fork rate across the system.
+
+As with any other resource under the CKRM framework, numtasks also assigns
+all the resources to the detault class(/rcfs/taskclass). Since , the number
+of tasks in a system is not limited, this resource controller provides a
+way to set the total number of tasks available in the system through the config
+file. By default this value is 128k(131072). In other words, if not changed,
+the total number of tasks allowed in a system is 131072.
+
+The config variable that affect this is sys_total_tasks.
+
+This resource controller also allows the sysadmin to limit the number of forks
+that are allowed in the system within the specified number of seconds. This
+can be acheived by changing the attributes forkrate and forkrate_interval in
+the config file. Through this feature one can protect the system from being
+attacked by fork bomb type applications.
+
+Installation
+-------------
+
+1. Configure "Number of Tasks Resource Manager" under CKRM (see
+      Documentation/ckrm/installation). This can be configured as a module
+      also. But, when inserted as a module it cannot be removed.
+
+2. Reboot the system with the new kernel. Insert the module, if compiled
+      as a module.
+
+3. Verify that the memory controller is present by reading the file
+   /rcfs/taskclass/config (should show a line with res=numtasks)
+
+Usage
+-----
+
+For brevity, unless otherwise specified all the following commands are
+executed in the default class (/rcfs/taskclass).
+
+As explained above the config file shows sys_total_tasks and forkrate
+info.
+
+   # cd /rcfs/taskclass
+   # cat config
+   res=numtasks,sys_total_tasks=131072,forkrate=1000000,forkrate_interval=3600
+
+By default, the sys_total_tasks is set to 131072(128k), and forkrate is set
+to 1 million and forkrate_interval is set to 3600 seconds. Which means the
+total number of tasks in a system is limited to 131072 and the forks are
+limited to 1 million per hour.
+
+sysadmin can change these values by just writing the attribute/value pair
+to the config file.
+
+   # echo res=numtasks,forkrate=100,forkrate_interval=10 > config
+   # cat config
+   res=numtasks,sys_total_tasks=1000,forkrate=100,forkrate_interval=10
+
+   # echo res=numtasks,forkrate=100,forkrate_interval=10 > config
+   # cat config
+   res=numtasks,sys_total_tasks=1000,forkrate=100,forkrate_interval=10
+
+By making total_guarantee and max_limit to be same as sys_total_tasks,
+sysadmin can make the numbers in shares file be same as the number of tasks
+for a class.
+
+   # echo res=numtasks,total_guarantee=131072,max_limit=131072 > shares
+   # cat shares
+   res=numtasks,guarantee=-2,limit=-2,total_guarantee=131072,max_limit=131072
+
+
+Class creation
+--------------
+
+   # mkdir c1
+
+Its initial share is don't care. The parent's share values will be unchanged.
+
+Setting a new class share
+-------------------------
+
+'guarantee' specifies the number of tasks this class is entitled to get
+'limit' is the maximum number of tasks this class can get.
+
+Following command will set the guarantee of class c1 to be 25000 and the limit
+to be 50000
+
+   # echo 'res=numtasks,guarantee=25000,limit=50000' > c1/shares
+   # cat c1/shares
+   res=numtasks,guarantee=25000,limit=50000,total_guarantee=100,max_limit=100
+
+Limiting forks in a time period
+-------------------------------
+By default, this resource controller allows forking of 1 million tasks in
+an hour.
+
+Folowing command would change it to allow only 100 forks per 10 seconds
+
+   # echo res=numtasks,forkrate=100,forkrate_interval=10 > config
+   # cat config
+   res=numtasks,sys_total_tasks=1000,forkrate=100,forkrate_interval=10
+
+Note that the same set of values is used across the system. In other words,
+each individual class will be allowed 'forkrate' forks in 'forkrate_interval'
+seconds.
+
+Monitoring
+----------
+
+stats file shows statistics of the number of tasks usage of a class
+[root@localhost taskclass]# cat stats
+Number of tasks resource:
+Total Over limit failures: 0
+Total Over guarantee sucesses: 0
+Total Over guarantee failures: 0
+Maximum Over limit failures: 0
+Maximum Over guarantee sucesses: 0
+Maximum Over guarantee failures: 0
+cur_alloc 38; borrowed 0; cnt_guar 131072; cnt_limit 131072 cnt_unused 131072, unused_guarantee 100, cur_max_limit 0
+
Index: linux-2.6.12-ckrm1/kernel/ckrm/ckrm_numtasks.c
===================================================================
--- linux-2.6.12-ckrm1.orig/kernel/ckrm/ckrm_numtasks.c	2005-06-20 15:04:50.000000000 -0700
+++ linux-2.6.12-ckrm1/kernel/ckrm/ckrm_numtasks.c	2005-06-20 15:04:51.000000000 -0700
@@ -36,6 +36,15 @@ static int total_cnt_alloc = 0;
 #define NUMTASKS_DEBUG
 #define NUMTASKS_NAME "numtasks"
 
+#define DEF_FORKRATE (1000000)		/* 1 million tasks */
+#define DEF_FORKRATE_INTERVAL (3600)    /* per hour */
+#define FORKRATE "forkrate"
+#define FORKRATE_INTERVAL "forkrate_interval"
+
+static int forkrate = DEF_FORKRATE;
+static int forkrate_interval = DEF_FORKRATE_INTERVAL;
+static struct ckrm_core_class *root_core;
+
 struct ckrm_numtasks {
 	struct ckrm_core_class *core;	/* the core i am part of... */
 	struct ckrm_core_class *parent;	/* parent of the core above. */
@@ -64,6 +73,10 @@ struct ckrm_numtasks {
 	int tot_limit_failures;
 	int tot_borrow_sucesses;
 	int tot_borrow_failures;
+
+	/* Fork rate fields */
+	int forks_in_period;
+	unsigned long period_start;
 };
 
 struct ckrm_res_ctlr numtasks_rcbs;
@@ -112,6 +125,7 @@ static int numtasks_get_ref_local(struct
 {
 	int rc, resid = numtasks_rcbs.resid, borrowed = 0;
 	struct ckrm_numtasks *res;
+	unsigned long now = jiffies, chg_at;
 
 	if ((resid < 0) || (core == NULL))
 		return 1;
@@ -182,8 +196,11 @@ static int numtasks_get_ref_local(struct
 
 	if (!rc)
 		atomic_dec(&res->cnt_cur_alloc);
-	else if (!borrowed)
+	else if (!borrowed) {
 		total_cnt_alloc++;
+		if (!force) /* force is not associated with a real fork. */
+			res->forks_in_period++;
+	}
 	return rc;
 }
 
@@ -233,6 +250,7 @@ static void *numtasks_res_alloc(struct c
  			res->cnt_guarantee = total_numtasks;
  			res->cnt_unused = total_numtasks;
  			res->cnt_limit = total_numtasks;
+			root_core = core; /* store the root core. */
 		}
 		try_module_get(THIS_MODULE);
 	} else {
@@ -432,29 +450,57 @@ static int numtasks_show_config(void *my
 
 	if (!res)
 		return -EINVAL;
-	seq_printf(sfile, "res=%s,%s=%d\n", NUMTASKS_NAME,
-		   SYS_TOTAL_TASKS, total_numtasks);
+	seq_printf(sfile, "res=%s,%s=%d,%s=%d,%s=%d\n", NUMTASKS_NAME,
+			SYS_TOTAL_TASKS, total_numtasks,
+			FORKRATE, forkrate,
+			FORKRATE_INTERVAL, forkrate_interval);
 	return 0;
 }
 
 enum numtasks_token_t {
 	numtasks_token_total,
+	numtasks_token_forkrate,
+	numtasks_token_interval,
 	numtasks_token_err
 };
 
 static match_table_t numtasks_tokens = {
 	{numtasks_token_total, SYS_TOTAL_TASKS "=%d"},
+	{numtasks_token_forkrate, FORKRATE "=%d"},
+	{numtasks_token_interval, FORKRATE_INTERVAL "=%d"},
 	{numtasks_token_err, NULL},
 };
 
+
+static void reset_forkrates(struct ckrm_core_class *parent, unsigned long now)
+{
+	struct ckrm_numtasks *parres;
+	struct ckrm_core_class *child = NULL;
+
+	parres = ckrm_get_res_class(parent, numtasks_rcbs.resid,
+				    struct ckrm_numtasks);
+	if (!parres) {
+		return;
+	}
+	parres->forks_in_period = 0;
+	parres->period_start = now;
+
+	ckrm_lock_hier(parent);
+	while ((child = ckrm_get_next_child(parent, child)) != NULL) {
+		reset_forkrates(child, now);
+	}
+	ckrm_unlock_hier(parent);
+}
+
 static int numtasks_set_config(void *my_res, const char *cfgstr)
 {
 	char *p;
 	struct ckrm_numtasks *res = my_res;
-	int new_total = 0;
+	int new_total, fr = 0, itvl = 0, err = 0;
 
 	if (!res)
 		return -EINVAL;
+
 	while ((p = strsep(&cfgstr, ",")) != NULL) {
 		substring_t args[MAX_OPT_ARGS];
 		int token;
@@ -464,26 +510,46 @@ static int numtasks_set_config(void *my_
 		token = match_token(p, numtasks_tokens, args);
 		switch (token) {
 		case numtasks_token_total:
-			if (match_int(args, &new_total))
-				return -EINVAL;
+			if (match_int(args, &new_total) ||
+						(new_total < total_cnt_alloc)) {
+				err = -EINVAL;
+			} else {
+				total_numtasks = new_total;
+				/*
+				 * res is the default class, as config is
+				 * present only in that directory.
+				 */
+				spin_lock(&res->cnt_lock);
+				res->cnt_guarantee = total_numtasks;
+				res->cnt_unused = total_numtasks;
+				res->cnt_limit = total_numtasks;
+				recalc_and_propagate(res, NULL);
+				spin_unlock(&res->cnt_lock);
+			}
+			break;
+		case numtasks_token_forkrate:
+			if (match_int(args, &fr) || (fr <= 0)) {
+				err = -EINVAL;
+			} else {
+				forkrate = fr;
+			}
+			break;
+		case numtasks_token_interval:
+			if (match_int(args, &itvl) || (itvl <= 0)) {
+				err = -EINVAL;
+			} else {
+				forkrate_interval = itvl;
+			}
 			break;
 		default:
-			return -EINVAL;
+			err = -EINVAL;
+			break;
 		}
 	}
-	if (new_total < total_cnt_alloc)
-		return -EINVAL;
-	total_numtasks = new_total;
 
-	/* res if the default class, as config is present only in
-	   that directory */
-	spin_lock(&res->cnt_lock);
-	res->cnt_guarantee = total_numtasks;
-	res->cnt_unused = total_numtasks;
-	res->cnt_limit = total_numtasks;
-	recalc_and_propagate(res, NULL);
-	spin_unlock(&res->cnt_lock);
-	return 0;
+	if ((fr > 0) || (itvl > 0))
+		reset_forkrates(root_core, jiffies);
+	return err;
 }
 
 static void numtasks_change_resclass(void *task, void *old, void *new)

--
-
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