Home page of this blog

Monday, November 29, 2010

Reinstalling grub after installing windows or after losing it

Recently my friend lost his grub after installing windows and he could not boot into Ubuntu. Long back we refered grub2 documentation from Ubuntu site and followed it to reinstall grub2. He asked me if I remembered it and I do

He asked me to post this as an article for his or anyone's easy reference and here it is for easy reference, if you lost your grub2 and unable to boot into any one of the following OS

 Ubuntu 10.04, Ubuntu 10.10, Linux Mint 9, Linux Mint 10, debian squeeze

His root ubuntu partition is in /dev/sda8 so I assume the reader of this article will take care to replace it with his root partition

Here are the steps to restore grub2 after your windows installation messes it up


Boot Ubuntu live cd (if you had installed 64 bit Ubuntu, then boot into 64 bit, otherwise use 32 bit, if u use a 32bit livecd to restore 64 bit or vice versa wont work!)

goto command line (use Applications --> Accessories --> Terminal or use Alt + F2 and gnome-terminal)




sudo mount /dev/sda<root partition number> /mnt

in my friends case it is sudo mount /dev/sda8 /mnt


sudo mount --bind /dev /mnt/dev
sudo mount --bind /dev/pts /mnt/dev/pts
sudo mount --bind /proc /mnt/proc
sudo mount --bind /sys /mnt/sys

sudo chroot /mnt

sudo update-grub

sync

grub-install /dev/sda

sync

exit

sync

sudo umount /mnt/sys
sudo umount /mnt/proc
sudo umount /mnt/dev/pts
sudo umount /mnt/dev
sudo umount /mnt


sudo reboot

Thursday, November 25, 2010

Enterprise Kernel 6 has SSD TRIM support

Today morning I successfully compiled Red Hat Enterprise Kernel 6 from source into a deb. The kernel is running excellently in Ubuntu. As an added bonus, I found that it already has SSD TRIM support

Now that I have an enterprise kernel as a debian binary and running, I tested SSD TRIM functionality with EL6 kernel

SSD TRIM is a wear levelling feature and supported from kernel versions 2.6.33 and above in ext4 filesystems. Though Enterprise Kernel 6 is in version 2.6.32 it has this TRIM functionality out of box for ext4. I think it has been backported into EL6 (exciting ....) and now I have it in Ubuntu (wow wow wow)

This is how I tested it

Before testing the SSD partition should be mounted with discard option,

Mount the SSD partition with a discard option, that is after the default options of SSD partition in /etc/fstab, say / for root SSD partition in /dev/sda1, it should look like below



/dev/sdb1 /  ext4    errors=remount-ro,noatime,discard  0       1




Use hdparm to test if discard is actually using TRIM to clear the bits in hardware

Here is how

1. Create a temporary file inside the SSD partition as root. Important change the directory to the SSD partition, from home partition if home is a harddisk partition

dd if=/dev/urandom of=tempfile count=100 bs=512k oflag=direct





2. Get the device sector of the tempfile generated and copy the first sector information after value 0

hdparm --fibmap tempfile



In the above example, the sector info I copied for testing is 802816 this will be a different value for the tempfile you generate

3. Read the sector using hdparm before deleting. Here I used the value I copied from previous step and gave as input to hdparm to read the sector info to see if it is non zero. Change the number after --read-sector to the value you got for hdparm --fibmap tempfile, dont blindly give 802816. /dev/sdb is my SSD harddisk, so I used that at the end, replace with the correct harddisk name

hdparm --read-sector 802816 /dev/sdb



4. Remove the tempfile and sync

rm tempfile && sync




5. Retry step 3 and the values displayed should all be zeroes, if TRIM is in action

hdparm --read-sector 802816 /dev/sdb




Kudos, if you came to this level, you probably tried, if your kernel supported TRIM for your SSD or know that Red Hat Enterprise 6  Kernel has TRIM feature in place already!

If you thought Ubuntu Long Term Support 10.04, kernel 2.6.32 has TRIM already, sorry, it does not have it yet. But EL6 kernel has TRIM support for SSD and it rocks!!

I have built the kernel deb of EL6 from source and you can follow my earlier blog to build it yourself as I have not yet hosted it

Wednesday, November 24, 2010

RH Enterprise Linux 6 kernel in Ubuntu

I want to taste what an enterprise kernel will look like. I have downloaded the Red Hat Enterprise linux kernel source rpm and extracted the source code. I am compiling the kernel as a debian package. Will update in next article about my experiments with enterprise linux kernel running in Ubuntu (if it runs)

Want to build your own kernel from source for Ubuntu, then follow my earlier blog about kernel compilation in ten steps

Update 1: I successfully compiled the debian packages of enterprise linux 6 kernel in Ubuntu. I got some compilation errors, but I used/merged the different config given by enterprise linux directory and spec file and got rid of the compilation errors. After the correct config, the kernel built successfully. The config I used to build the el6 kernel is here


Thursday, November 18, 2010

Kernel compilation in ten steps -- Ubuntu

Introduction: Last article I mentioned about how I did kernel compilation from source code. Here is a step by step how to.

This kernel compilation article will work for debian and debian based distros (and of course Ubuntu)

Step 1: Fetch kernel source

Browse http://www.kernel.org and choose a stable version and click full source

For e.g 2.6.34.7

To know more about the stability and features of a certain kernel version visit http://kernelnewbies.org  http://www.h-online.com and http://www.phoronix.com

Decide on the stable version based on your requirements and stability

Step 2: Install kernel build dependencies in debian/ubuntu

sudo apt-get install kernel-package libncurses5 libncurses5-dev


If you are a debian user, become root and use apt-get/aptitude directly to install kernel-package and libncurses5. After installing become normal user and follow steps below

Step 3:  Extract the source code

Unzip/untar the zip file of the kernel source code. Now enter into the directory of the extracted source code.

Step 4: Prepare config for kernel compilation

Step 4.1: make clean && make mrproper
Step 4.2: make menuconfig


This will open the kernel configuration, change/hack settings to your hearts content. By default make menuconfig copies your currently running kernel configuration. If you want a different configuration, copy that to .config file before launching make menuconfig. If you want to start fresh, use make defconfig before calling make menuconfig

Step 5: Make the kernel deb files after cleaning

Step 5.1: make-kpkg clean

Step 5.2:  do a build, based on your processor power, this will take some time. For example, my system compiles within 15 minutes since it is a quad core with hyperthreading. use CONCURRENCY_LEVEL=n, where n is the processor count

Core 2 duo/dual core processor owners
CONCURRENCY_LEVEL=2 fakeroot make-kpkg  --initrd --append-to-version=-shortdescription kernel_image kernel_headers


Quad core processor owners

CONCURRENCY_LEVEL=4 fakeroot make-kpkg  --initrd --append-to-version=-shortdescription kernel_image kernel_headers

Quad core with hyperthreading
CONCURRENCY_LEVEL=8 fakeroot make-kpkg  --initrd --append-to-version=-shortdescription kernel_image kernel_headers

Hexa core
CONCURRENCY_LEVEL=6 fakeroot make-kpkg  --initrd --append-to-version=-shortdescription kernel_image kernel_headers

Hexa core with hyperthreading
CONCURRENCY_LEVEL=12 fakeroot make-kpkg  --initrd --append-to-version=-shortdescription kernel_image kernel_headers

Once the compilation, linking is complete proceed to next step



Step 6: Install the debian packages

Change to previous directory, where the kernel packages are built as debian binary. There should be a header and a image deb file. Just use the following command to install the deb

cd .. && sudo dpkg -i *.deb


Step 7: Create a initrd

sudo update-initramfs -c -k <kernel version>

for e.g since I compiled 2.6.34.7, I used 

sudo update-initramfs -c -k 2.6.34.7

Now after this step, update your grub

Step 8: Update grub with new initrd

sudo update-grub

Step 9: Reboot

sudo reboot

Step 10: Enjoy!!

200 line linux patch backport to ubuntu 2.6.32

Today I tried to backport the 200 line linux patch for improving responsiveness

Here is the patch




diff -urN linux-2.6.32/Documentation/kernel-parameters.txt linux/Documentation/kernel-parameters.txt
--- linux-2.6.32/Documentation/kernel-parameters.txt    2010-10-31 16:13:19.000000000 +0530
+++ linux/Documentation/kernel-parameters.txt    2010-11-18 10:05:50.027037654 +0530
@@ -1618,6 +1618,9 @@
     noapic        [SMP,APIC] Tells the kernel to not make use of any
             IOAPICs that may be present in the system.


+    noautogroup    Disable scheduler automatic task group creation.
+
+
     nobats        [PPC] Do not use BATs for mapping kernel lowmem
             on "Classic" PPC cores.


diff -urN linux-2.6.32/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- linux-2.6.32/drivers/char/tty_io.c    2010-10-31 16:13:19.000000000 +0530
+++ linux/drivers/char/tty_io.c    2010-11-18 10:06:51.637609197 +0530
@@ -3029,6 +3029,8 @@
     put_pid(tsk->signal->tty_old_pgrp);
     tsk->signal->tty = tty_kref_get(tty);
     tsk->signal->tty_old_pgrp = NULL;
+
+    sched_autogroup_create_attach(tsk);
 }


 static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
diff -urN linux-2.6.32/include/linux/sched.h linux/include/linux/sched.h
--- linux-2.6.32/include/linux/sched.h    2010-10-31 16:13:19.000000000 +0530
+++ linux/include/linux/sched.h    2010-11-18 09:45:08.517579562 +0530
@@ -556,6 +556,8 @@
     spinlock_t lock;
 };


+struct autogroup;
+
 /*
  * NOTE! "signal_struct" does not have it's own
  * locking, because a shared signal_struct always
@@ -622,6 +624,10 @@


     struct tty_struct *tty; /* NULL if no tty */


+#ifdef CONFIG_SCHED_AUTOGROUP
+    struct autogroup *autogroup;
+#endif
+
     /*
      * Cumulative resource counters for dead threads in the group,
      * and for reaped dead child processes forked by this group.
@@ -1939,6 +1945,22 @@


 extern unsigned int sysctl_sched_compat_yield;


+#ifdef CONFIG_SCHED_AUTOGROUP
+extern unsigned int sysctl_sched_autogroup_enabled;
+
+extern void sched_autogroup_create_attach(struct task_struct *p);
+extern void sched_autogroup_detach(struct task_struct *p);
+extern void sched_autogroup_fork(struct signal_struct *sig);
+extern void sched_autogroup_exit(struct signal_struct *sig);
+#else
+static inline void sched_autogroup_create_attach(struct task_struct *p) { }
+static inline void sched_autogroup_detach(struct task_struct *p) { }
+static inline void sched_autogroup_fork(struct signal_struct *sig) { }
+static inline void sched_autogroup_exit(struct signal_struct *sig) { }
+#endif
+
+
+
 #ifdef CONFIG_RT_MUTEXES
 extern int rt_mutex_getprio(struct task_struct *p);
 extern void rt_mutex_setprio(struct task_struct *p, int prio);
diff -urN linux-2.6.32/init/Kconfig linux/init/Kconfig
--- linux-2.6.32/init/Kconfig    2010-10-31 16:13:19.000000000 +0530
+++ linux/init/Kconfig    2010-11-18 10:04:56.430328910 +0530
@@ -608,6 +608,19 @@


 endif # CGROUPS


+config SCHED_AUTOGROUP
+    bool "Automatic process group scheduling"
+    select CGROUPS
+    select CGROUP_SCHED
+    select FAIR_GROUP_SCHED
+    help
+      This option optimizes the scheduler for common desktop workloads by
+      automatically creating and populating task groups.  This separation
+      of workloads isolates aggressive CPU burners (like build jobs) from
+      desktop applications.  Task group autogeneration is currently based
+      upon task tty association.
+
+
 config MM_OWNER
     bool


diff -urN linux-2.6.32/kernel/fork.c linux/kernel/fork.c
--- linux-2.6.32/kernel/fork.c    2010-10-31 16:13:19.000000000 +0530
+++ linux/kernel/fork.c    2010-11-18 10:10:19.796963164 +0530
@@ -908,6 +908,8 @@


     tty_audit_fork(sig);


+    sched_autogroup_fork(sig);
+
     sig->oom_adj = current->signal->oom_adj;


     return 0;
diff -urN linux-2.6.32/kernel/sched_autogroup.c linux/kernel/sched_autogroup.c
--- linux-2.6.32/kernel/sched_autogroup.c    1970-01-01 05:30:00.000000000 +0530
+++ linux/kernel/sched_autogroup.c    2010-11-17 22:43:28.726509000 +0530
@@ -0,0 +1,140 @@
+#ifdef CONFIG_SCHED_AUTOGROUP
+
+unsigned int __read_mostly sysctl_sched_autogroup_enabled = 1;
+
+struct autogroup {
+    struct kref        kref;
+    struct task_group    *tg;
+};
+
+static struct autogroup autogroup_default;
+
+static void autogroup_init(struct task_struct *init_task)
+{
+    autogroup_default.tg = &init_task_group;
+    kref_init(&autogroup_default.kref);
+    init_task->signal->autogroup = &autogroup_default;
+}
+
+static inline void autogroup_destroy(struct kref *kref)
+{
+    struct autogroup *ag = container_of(kref, struct autogroup, kref);
+    struct task_group *tg = ag->tg;
+
+    kfree(ag);
+    sched_destroy_group(tg);
+}
+
+static inline void autogroup_kref_put(struct autogroup *ag)
+{
+    kref_put(&ag->kref, autogroup_destroy);
+}
+
+static inline struct autogroup *autogroup_kref_get(struct autogroup *ag)
+{
+    kref_get(&ag->kref);
+    return ag;
+}
+
+static inline struct autogroup *autogroup_create(void)
+{
+    struct autogroup *ag = kmalloc(sizeof(*ag), GFP_KERNEL);
+
+    if (!ag)
+        goto out_fail;
+
+    ag->tg = sched_create_group(&init_task_group);
+    kref_init(&ag->kref);
+
+    if (!(IS_ERR(ag->tg)))
+        return ag;
+
+out_fail:
+    if (ag) {
+        kfree(ag);
+        WARN_ON(1);
+    } else
+        WARN_ON(1);
+
+    return autogroup_kref_get(&autogroup_default);
+}
+
+static inline struct task_group *
+autogroup_task_group(struct task_struct *p, struct task_group *tg)
+{
+    int enabled = ACCESS_ONCE(sysctl_sched_autogroup_enabled);
+
+    enabled &= (tg == &root_task_group);
+    enabled &= (p->sched_class == &fair_sched_class);
+    enabled &= (!(p->flags & PF_EXITING));
+
+    if (enabled)
+        return p->signal->autogroup->tg;
+
+    return tg;
+}
+
+static void
+autogroup_move_group(struct task_struct *p, struct autogroup *ag)
+{
+    struct autogroup *prev;
+    struct task_struct *t;
+    struct rq *rq;
+    unsigned long flags;
+
+    rq = task_rq_lock(p, &flags);
+    prev = p->signal->autogroup;
+    if (prev == ag) {
+        task_rq_unlock(rq, &flags);
+        return;
+    }
+
+    p->signal->autogroup = autogroup_kref_get(ag);
+    __sched_move_task(p, rq);
+    task_rq_unlock(rq, &flags);
+
+    rcu_read_lock();
+    list_for_each_entry_rcu(t, &p->thread_group, thread_group) {
+        sched_move_task(t);
+    }
+    rcu_read_unlock();
+
+    autogroup_kref_put(prev);
+}
+
+void sched_autogroup_create_attach(struct task_struct *p)
+{
+    struct autogroup *ag = autogroup_create();
+
+    autogroup_move_group(p, ag);
+    /* drop extra refrence added by autogroup_create() */
+    autogroup_kref_put(ag);
+}
+EXPORT_SYMBOL(sched_autogroup_create_attach);
+
+/* currently has no users */
+void sched_autogroup_detach(struct task_struct *p)
+{
+    autogroup_move_group(p, &autogroup_default);
+}
+EXPORT_SYMBOL(sched_autogroup_detach);
+
+void sched_autogroup_fork(struct signal_struct *sig)
+{
+    sig->autogroup = autogroup_kref_get(current->signal->autogroup);
+}
+
+void sched_autogroup_exit(struct signal_struct *sig)
+{
+    autogroup_kref_put(sig->autogroup);
+}
+
+static int __init setup_autogroup(char *str)
+{
+    sysctl_sched_autogroup_enabled = 0;
+
+    return 1;
+}
+
+__setup("noautogroup", setup_autogroup);
+#endif
diff -urN linux-2.6.32/kernel/sched_autogroup.h linux/kernel/sched_autogroup.h
--- linux-2.6.32/kernel/sched_autogroup.h    1970-01-01 05:30:00.000000000 +0530
+++ linux/kernel/sched_autogroup.h    2010-11-17 22:39:46.575555000 +0530
@@ -0,0 +1,18 @@
+#ifdef CONFIG_SCHED_AUTOGROUP
+
+static void __sched_move_task(struct task_struct *tsk, struct rq *rq);
+
+static inline struct task_group *
+autogroup_task_group(struct task_struct *p, struct task_group *tg);
+
+#else /* !CONFIG_SCHED_AUTOGROUP */
+
+static inline void autogroup_init(struct task_struct *init_task) {  }
+
+static inline struct task_group *
+autogroup_task_group(struct task_struct *p, struct task_group *tg)
+{
+    return tg;
+}
+
+#endif /* CONFIG_SCHED_AUTOGROUP */
diff -urN linux-2.6.32/kernel/sched.c linux/kernel/sched.c
--- linux-2.6.32/kernel/sched.c    2010-10-31 16:13:19.000000000 +0530
+++ linux/kernel/sched.c    2010-11-18 10:01:01.377697053 +0530
@@ -76,6 +76,7 @@
 #include

 #include "sched_cpupri.h"
+#include "sched_autogroup.h"

 #define CREATE_TRACE_POINTS
 #include
@@ -346,19 +347,31 @@
 /* return group to which a task belongs */
 static inline struct task_group *task_group(struct task_struct *p)
 {
-    struct task_group *tg;

 #ifdef CONFIG_USER_SCHED
+    struct task_group *tg;
+
     rcu_read_lock();
     tg = __task_cred(p)->user->tg;
     rcu_read_unlock();
+
+    return tg;
 #elif defined(CONFIG_CGROUP_SCHED)
-    tg = container_of(task_subsys_state(p, cpu_cgroup_subsys_id),
-                struct task_group, css);
+    struct task_group *tg;
+     struct cgroup_subsys_state *css;
+
+    css = task_subsys_state(p, cpu_cgroup_subsys_id);
+
+    tg = container_of(css, struct task_group, css);
+
+    return autogroup_task_group(p, tg);
 #else
+    struct task_group *tg;
+
     tg = &init_task_group;
-#endif
+
     return tg;
+#endif
 }

 /* Change a task's cfs_rq and parent entity if it moves across CPUs/groups */
@@ -1826,6 +1839,7 @@
 #include "sched_idletask.c"
 #include "sched_fair.c"
 #include "sched_rt.c"
+#include "sched_autogroup.c"
 #ifdef CONFIG_SCHED_DEBUG
 # include "sched_debug.c"
 #endif
@@ -9558,6 +9572,8 @@
     init_task_group.parent = &root_task_group;
     list_add(&init_task_group.siblings, &root_task_group.children);
 #endif /* CONFIG_USER_SCHED */
+
+    autogroup_init(&init_task);
 #endif /* CONFIG_GROUP_SCHED */

 #if defined CONFIG_FAIR_GROUP_SCHED && defined CONFIG_SMP
@@ -10097,15 +10113,11 @@
 /* change task's runqueue when it moves between groups.
  *    The caller of this function should have put the task in its new group
  *    by now. This function just updates tsk->se.cfs_rq and tsk->se.parent to
- *    reflect its new group.
+ *    reflect its new group.  Called with the runqueue lock held.
  */
-void sched_move_task(struct task_struct *tsk)
+void __sched_move_task(struct task_struct *tsk, struct rq *rq)
 {
     int on_rq, running;
-    unsigned long flags;
-    struct rq *rq;
-
-    rq = task_rq_lock(tsk, &flags);

     update_rq_clock(rq);

@@ -10128,6 +10140,15 @@
         tsk->sched_class->set_curr_task(rq);
     if (on_rq)
         enqueue_task(rq, tsk, 0);
+}
+
+void sched_move_task(struct task_struct *tsk)
+{
+    struct rq *rq;
+    unsigned long flags;
+
+    rq = task_rq_lock(tsk, &flags);
+    __sched_move_task(tsk, rq);

     task_rq_unlock(rq, &flags);
 }
diff -urN linux-2.6.32/kernel/sysctl.c linux/kernel/sysctl.c
--- linux-2.6.32/kernel/sysctl.c    2010-10-31 16:13:19.000000000 +0530
+++ linux/kernel/sysctl.c    2010-11-18 10:03:11.533818737 +0530
@@ -379,6 +379,18 @@
         .mode        = 0644,
         .proc_handler    = &proc_dointvec,
     },
+#ifdef CONFIG_SCHED_AUTOGROUP
+    {
+        .ctl_name    = CTL_UNNUMBERED,
+        .procname    = "sched_autogroup_enabled",
+        .data        = &sysctl_sched_autogroup_enabled,
+        .maxlen        = sizeof(unsigned int),
+        .mode        = 0644,
+        .proc_handler    = proc_dointvec,
+        .extra1        = &zero,
+        .extra2        = &one,
+    },
+#endif
 #ifdef CONFIG_PROVE_LOCKING
     {
         .ctl_name    = CTL_UNNUMBERED, 

200 line linux kernel patch backport to 2.6.34.7

Today morning I read about 200 line linux kernel patch that does wonders here. I found that the patch is for 2.6.37 and increases responsiveness of desktop by 10 times max to 60 times average

It got my curiosity aroused and I wanted to see it in action.

I downloaded the patch from here and tried to  backport it to 2.6.34.7 (downloaded from here)

My maiden attempt to backport the patch succeeded and I compiled and installed the deb file

Here is the backport patch content



diff -urN linux-2.6.34.7/Documentation/kernel-parameters.txt linux/Documentation/kernel-parameters.txt
--- linux-2.6.34.7/Documentation/kernel-parameters.txt    2010-09-13 22:24:58.000000000 +0530
+++ linux/Documentation/kernel-parameters.txt    2010-11-17 22:49:10.082513013 +0530
@@ -1643,6 +1643,9 @@
     noapic        [SMP,APIC] Tells the kernel to not make use of any
             IOAPICs that may be present in the system.

+    noautogroup    Disable scheduler automatic task group creation.
+
+
     nobats        [PPC] Do not use BATs for mapping kernel lowmem
             on "Classic" PPC cores.

diff -urN linux-2.6.34.7/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- linux-2.6.34.7/drivers/char/tty_io.c    2010-09-13 22:24:58.000000000 +0530
+++ linux/drivers/char/tty_io.c    2010-11-17 22:38:38.750591065 +0530
@@ -3049,6 +3049,7 @@
     put_pid(tsk->signal->tty_old_pgrp);
     tsk->signal->tty = tty_kref_get(tty);
     tsk->signal->tty_old_pgrp = NULL;
+    sched_autogroup_create_attach(tsk);
 }

 static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
diff -urN linux-2.6.34.7/include/linux/sched.h linux/include/linux/sched.h
--- linux-2.6.34.7/include/linux/sched.h    2010-09-13 22:24:58.000000000 +0530
+++ linux/include/linux/sched.h    2010-11-17 21:40:45.286509459 +0530
@@ -514,6 +514,8 @@
     spinlock_t lock;
 };

+struct autogroup;
+
 /*
  * NOTE! "signal_struct" does not have it's own
  * locking, because a shared signal_struct always
@@ -580,6 +582,9 @@

     struct tty_struct *tty; /* NULL if no tty */

+#ifdef CONFIG_SCHED_AUTOGROUP
+    struct autogroup *autogroup;
+#endif
     /*
      * Cumulative resource counters for dead threads in the group,
      * and for reaped dead child processes forked by this group.
@@ -1904,6 +1909,21 @@

 extern unsigned int sysctl_sched_compat_yield;

+#ifdef CONFIG_SCHED_AUTOGROUP
+extern unsigned int sysctl_sched_autogroup_enabled;
+
+extern void sched_autogroup_create_attach(struct task_struct *p);
+extern void sched_autogroup_detach(struct task_struct *p);
+extern void sched_autogroup_fork(struct signal_struct *sig);
+extern void sched_autogroup_exit(struct signal_struct *sig);
+#else
+static inline void sched_autogroup_create_attach(struct task_struct *p) { }
+static inline void sched_autogroup_detach(struct task_struct *p) { }
+static inline void sched_autogroup_fork(struct signal_struct *sig) { }
+static inline void sched_autogroup_exit(struct signal_struct *sig) { }
+#endif
+
+
 #ifdef CONFIG_RT_MUTEXES
 extern int rt_mutex_getprio(struct task_struct *p);
 extern void rt_mutex_setprio(struct task_struct *p, int prio);
diff -urN linux-2.6.34.7/init/Kconfig linux/init/Kconfig
--- linux-2.6.34.7/init/Kconfig    2010-09-13 22:24:58.000000000 +0530
+++ linux/init/Kconfig    2010-11-17 22:48:16.986827765 +0530
@@ -614,6 +614,18 @@

 endif # CGROUPS

+config SCHED_AUTOGROUP
+    bool "Automatic process group scheduling"
+    select CGROUPS
+    select CGROUP_SCHED
+    select FAIR_GROUP_SCHED
+    help
+      This option optimizes the scheduler for common desktop workloads by
+      automatically creating and populating task groups.  This separation
+      of workloads isolates aggressive CPU burners (like build jobs) from
+      desktop applications.  Task group autogeneration is currently based
+      upon task tty association.
+
 config MM_OWNER
     bool

diff -urN linux-2.6.34.7/kernel/fork.c linux/kernel/fork.c
--- linux-2.6.34.7/kernel/fork.c    2010-09-13 22:24:58.000000000 +0530
+++ linux/kernel/fork.c    2010-11-17 22:35:27.942763006 +0530
@@ -886,6 +886,8 @@
     posix_cpu_timers_init_group(sig);

     tty_audit_fork(sig);
+    sched_autogroup_fork(sig);
+

     sig->oom_adj = current->signal->oom_adj;

diff -urN linux-2.6.34.7/kernel/sched_autogroup.c linux/kernel/sched_autogroup.c
--- linux-2.6.34.7/kernel/sched_autogroup.c    1970-01-01 05:30:00.000000000 +0530
+++ linux/kernel/sched_autogroup.c    2010-11-17 22:43:28.726509874 +0530
@@ -0,0 +1,140 @@
+#ifdef CONFIG_SCHED_AUTOGROUP
+
+unsigned int __read_mostly sysctl_sched_autogroup_enabled = 1;
+
+struct autogroup {
+    struct kref        kref;
+    struct task_group    *tg;
+};
+
+static struct autogroup autogroup_default;
+
+static void autogroup_init(struct task_struct *init_task)
+{
+    autogroup_default.tg = &init_task_group;
+    kref_init(&autogroup_default.kref);
+    init_task->signal->autogroup = &autogroup_default;
+}
+
+static inline void autogroup_destroy(struct kref *kref)
+{
+    struct autogroup *ag = container_of(kref, struct autogroup, kref);
+    struct task_group *tg = ag->tg;
+
+    kfree(ag);
+    sched_destroy_group(tg);
+}
+
+static inline void autogroup_kref_put(struct autogroup *ag)
+{
+    kref_put(&ag->kref, autogroup_destroy);
+}
+
+static inline struct autogroup *autogroup_kref_get(struct autogroup *ag)
+{
+    kref_get(&ag->kref);
+    return ag;
+}
+
+static inline struct autogroup *autogroup_create(void)
+{
+    struct autogroup *ag = kmalloc(sizeof(*ag), GFP_KERNEL);
+
+    if (!ag)
+        goto out_fail;
+
+    ag->tg = sched_create_group(&init_task_group);
+    kref_init(&ag->kref);
+
+    if (!(IS_ERR(ag->tg)))
+        return ag;
+
+out_fail:
+    if (ag) {
+        kfree(ag);
+        WARN_ON(1);
+    } else
+        WARN_ON(1);
+
+    return autogroup_kref_get(&autogroup_default);
+}
+
+static inline struct task_group *
+autogroup_task_group(struct task_struct *p, struct task_group *tg)
+{
+    int enabled = ACCESS_ONCE(sysctl_sched_autogroup_enabled);
+
+    enabled &= (tg == &root_task_group);
+    enabled &= (p->sched_class == &fair_sched_class);
+    enabled &= (!(p->flags & PF_EXITING));
+
+    if (enabled)
+        return p->signal->autogroup->tg;
+
+    return tg;
+}
+
+static void
+autogroup_move_group(struct task_struct *p, struct autogroup *ag)
+{
+    struct autogroup *prev;
+    struct task_struct *t;
+    struct rq *rq;
+    unsigned long flags;
+
+    rq = task_rq_lock(p, &flags);
+    prev = p->signal->autogroup;
+    if (prev == ag) {
+        task_rq_unlock(rq, &flags);
+        return;
+    }
+
+    p->signal->autogroup = autogroup_kref_get(ag);
+    __sched_move_task(p, rq);
+    task_rq_unlock(rq, &flags);
+
+    rcu_read_lock();
+    list_for_each_entry_rcu(t, &p->thread_group, thread_group) {
+        sched_move_task(t);
+    }
+    rcu_read_unlock();
+
+    autogroup_kref_put(prev);
+}
+
+void sched_autogroup_create_attach(struct task_struct *p)
+{
+    struct autogroup *ag = autogroup_create();
+
+    autogroup_move_group(p, ag);
+    /* drop extra refrence added by autogroup_create() */
+    autogroup_kref_put(ag);
+}
+EXPORT_SYMBOL(sched_autogroup_create_attach);
+
+/* currently has no users */
+void sched_autogroup_detach(struct task_struct *p)
+{
+    autogroup_move_group(p, &autogroup_default);
+}
+EXPORT_SYMBOL(sched_autogroup_detach);
+
+void sched_autogroup_fork(struct signal_struct *sig)
+{
+    sig->autogroup = autogroup_kref_get(current->signal->autogroup);
+}
+
+void sched_autogroup_exit(struct signal_struct *sig)
+{
+    autogroup_kref_put(sig->autogroup);
+}
+
+static int __init setup_autogroup(char *str)
+{
+    sysctl_sched_autogroup_enabled = 0;
+
+    return 1;
+}
+
+__setup("noautogroup", setup_autogroup);
+#endif
diff -urN linux-2.6.34.7/kernel/sched_autogroup.h linux/kernel/sched_autogroup.h
--- linux-2.6.34.7/kernel/sched_autogroup.h    1970-01-01 05:30:00.000000000 +0530
+++ linux/kernel/sched_autogroup.h    2010-11-17 22:39:46.575555847 +0530
@@ -0,0 +1,18 @@
+#ifdef CONFIG_SCHED_AUTOGROUP
+
+static void __sched_move_task(struct task_struct *tsk, struct rq *rq);
+
+static inline struct task_group *
+autogroup_task_group(struct task_struct *p, struct task_group *tg);
+
+#else /* !CONFIG_SCHED_AUTOGROUP */
+
+static inline void autogroup_init(struct task_struct *init_task) {  }
+
+static inline struct task_group *
+autogroup_task_group(struct task_struct *p, struct task_group *tg)
+{
+    return tg;
+}
+
+#endif /* CONFIG_SCHED_AUTOGROUP */
diff -urN linux-2.6.34.7/kernel/sched.c linux/kernel/sched.c
--- linux-2.6.34.7/kernel/sched.c    2010-09-13 22:24:58.000000000 +0530
+++ linux/kernel/sched.c    2010-11-17 22:04:34.054508727 +0530
@@ -77,6 +77,7 @@
 #include

 #include "sched_cpupri.h"
+#include "sched_autogroup.h"

 #define CREATE_TRACE_POINTS
 #include
@@ -311,13 +312,20 @@
 {
     struct task_group *tg;

+
 #ifdef CONFIG_CGROUP_SCHED
-    tg = container_of(task_subsys_state(p, cpu_cgroup_subsys_id),
-                struct task_group, css);
+     struct cgroup_subsys_state *css;
+
+    css = task_subsys_state(p, cpu_cgroup_subsys_id);
+
+    tg = container_of(css, struct task_group, css);
+
+    return autogroup_task_group(p, tg);
 #else
     tg = &init_task_group;
-#endif
+
     return tg;
+#endif
 }

 /* Change a task's cfs_rq and parent entity if it moves across CPUs/groups */
@@ -1935,6 +1943,7 @@
 #include "sched_idletask.c"
 #include "sched_fair.c"
 #include "sched_rt.c"
+#include "sched_autogroup.c"
 #ifdef CONFIG_SCHED_DEBUG
 # include "sched_debug.c"
 #endif
@@ -7738,7 +7747,7 @@
 #ifdef CONFIG_CGROUP_SCHED
     list_add(&init_task_group.list, &task_groups);
     INIT_LIST_HEAD(&init_task_group.children);
-
+    autogroup_init(&init_task);
 #endif /* CONFIG_CGROUP_SCHED */

 #if defined CONFIG_FAIR_GROUP_SCHED && defined CONFIG_SMP
@@ -8257,15 +8266,11 @@
 /* change task's runqueue when it moves between groups.
  *    The caller of this function should have put the task in its new group
  *    by now. This function just updates tsk->se.cfs_rq and tsk->se.parent to
- *    reflect its new group.
+ *    reflect its new group.  Called with the runqueue lock held.
  */
-void sched_move_task(struct task_struct *tsk)
+void __sched_move_task(struct task_struct *tsk, struct rq *rq)
 {
     int on_rq, running;
-    unsigned long flags;
-    struct rq *rq;
-
-    rq = task_rq_lock(tsk, &flags);

     update_rq_clock(rq);

@@ -8288,6 +8293,15 @@
         tsk->sched_class->set_curr_task(rq);
     if (on_rq)
         enqueue_task(rq, tsk, 0, false);
+}
+
+void sched_move_task(struct task_struct *tsk)
+{
+    struct rq *rq;
+    unsigned long flags;
+
+    rq = task_rq_lock(tsk, &flags);
+    __sched_move_task(tsk, rq);

     task_rq_unlock(rq, &flags);
 }
diff -urN linux-2.6.34.7/kernel/sysctl.c linux/kernel/sysctl.c
--- linux-2.6.34.7/kernel/sysctl.c    2010-09-13 22:24:58.000000000 +0530
+++ linux/kernel/sysctl.c    2010-11-17 22:45:38.558806407 +0530
@@ -354,6 +354,17 @@
         .mode        = 0644,
         .proc_handler    = proc_dointvec,
     },
+#ifdef CONFIG_SCHED_AUTOGROUP
+    {
+        .procname    = "sched_autogroup_enabled",
+        .data        = &sysctl_sched_autogroup_enabled,
+        .maxlen        = sizeof(unsigned int),
+        .mode        = 0644,
+        .proc_handler    = proc_dointvec,
+        .extra1        = &zero,
+        .extra2        = &one,
+    },
+#endif
 #ifdef CONFIG_PROVE_LOCKING
     {
         .procname    = "prove_locking",