tuna: Make --isolate/--include operations affect /proc/irq/default_smp_affinity

When isolating CPUs we affect the IRQ smp_affinity masks, but that will not
affect new devices, to make the isolation operation to stick for that case too we
need to remove the isolated CPUs from the /proc/irq/default_smp_affinity file,
that is what is used to set the initial affinity mask for new device IRQs.

E.g.:

[root@emilia git]# tuna -q enp21s0f0-* -Q
   # users            affinity
  66 enp21s0f0-TxRx-0     0xff  ixgbe
  67 enp21s0f0-TxRx-1     0xff  ixgbe
  68 enp21s0f0-TxRx-2     0xff  ixgbe
  69 enp21s0f0-TxRx-3     0xff  ixgbe
[root@emilia git]# cat /proc/irq/default_smp_affinity
ff
[root@emilia git]# tuna -S1 --isolate
[root@emilia git]# tuna -q enp21s0f0-* -Q
   # users            affinity
  66 enp21s0f0-TxRx-0  0,2,4,6  ixgbe
  67 enp21s0f0-TxRx-1  0,2,4,6  ixgbe
  68 enp21s0f0-TxRx-2  0,2,4,6  ixgbe
  69 enp21s0f0-TxRx-3  0,2,4,6  ixgbe
[root@emilia git]# cat /proc/irq/default_smp_affinity
55
>>> hex((1 << 0) | (1 << 2) | (1 << 4) | (1 << 6))
'0x55'
[root@emilia git]# tuna --cpu 6 --isolate
[root@emilia git]# tuna -q enp21s0f0-* -Q
   # users            affinity
  66 enp21s0f0-TxRx-0    0,2,4  ixgbe
  67 enp21s0f0-TxRx-1    0,2,4  ixgbe
  68 enp21s0f0-TxRx-2    0,2,4  ixgbe
  69 enp21s0f0-TxRx-3    0,2,4  ixgbe
[root@emilia git]# cat /proc/irq/default_smp_affinity
15
>>> hex((1 << 0) | (1 << 2) | (1 << 4))
'0x15'
[root@emilia git]# tuna --cpu 1 --include
[root@emilia git]# tuna -q enp21s0f0-* -Q
   # users            affinity
  66 enp21s0f0-TxRx-0  0,1,2,4  ixgbe
  67 enp21s0f0-TxRx-1  0,1,2,4  ixgbe
  68 enp21s0f0-TxRx-2  0,1,2,4  ixgbe
  69 enp21s0f0-TxRx-3  0,1,2,4  ixgbe
[root@emilia git]# cat /proc/irq/default_smp_affinity
17
>>> hex((1 << 0) | (1 << 1) | (1 << 2) | (1 << 4))
'0x17'

Requested-by: Luiz Capitulino <lcapitulino@redhat.com>
Cc: Clark Williams <williams@redhat.com>
Cc: Guy Streeter <streeter@redhat.com>
Cc: Jeremy Eder <jeder@redhat.com>
Cc: Jiri Kastner <jkastner@redhat.com>
Cc: John Kacur <jkacur@redhat.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
diff --git a/tuna/tuna.py b/tuna/tuna.py
index 7b839f1..0efa84f 100755
--- a/tuna/tuna.py
+++ b/tuna/tuna.py
@@ -3,6 +3,7 @@
 
 import copy, ethtool, os, procfs, re, schedutils
 import help, fnmatch
+from procfs import utilist
 
 try:
 	set
@@ -92,9 +93,10 @@
 	irq_re = re.compile("(irq/[0-9]+-.+|IRQ-[0-9]+)")
 	return len(ps.find_by_regex(irq_re)) > 0
 
-def set_irq_affinity(irq, bitmasklist):
+def set_irq_affinity_filename(filename, bitmasklist):
+	pathname="/proc/irq/%s" % filename
+	f = file(pathname, "w")
 	text = ",".join(map(lambda a: "%x" % a, bitmasklist))
-	f = file("/proc/irq/%d/smp_affinity" % irq, "w")
 	f.write("%s\n" % text)
 	try:
 		f.close()
@@ -103,6 +105,9 @@
 		return False
 	return True
 
+def set_irq_affinity(irq, bitmasklist):
+	return set_irq_affinity_filename("%d/smp_affinity" % irq, bitmasklist)
+
 def cpustring_to_list(cpustr):
 	"""Convert a string of numbers to an integer list.
     
@@ -307,6 +312,14 @@
 		affinity = list(set(affinity) - set(cpus))
 	return affinity
 
+# Shound be moved to python_linux_procfs.interrupts, shared with interrupts.parse_affinity, etc.
+def parse_irq_affinity_filename(filename, nr_cpus):
+	f = file("/proc/irq/%s" % filename)
+	line = f.readline()
+	f.close()
+	return utilist.bitmasklist(line, nr_cpus)
+
+
 def isolate_cpus(cpus, nr_cpus):
 	ps = procfs.pidstats()
 	ps.reload_threads()
@@ -369,6 +382,10 @@
 					 procfs.hexbitmask(affinity,
 							   nr_cpus))
 
+	affinity = parse_irq_affinity_filename("default_smp_affinity", nr_cpus)
+	affinity = affinity_remove_cpus(affinity, cpus, nr_cpus)
+	set_irq_affinity_filename("default_smp_affinity", procfs.hexbitmask(affinity, nr_cpus))
+
 	return (previous_pid_affinities, previous_irq_affinities)
 
 def include_cpus(cpus, nr_cpus):
@@ -432,6 +449,10 @@
 			set_irq_affinity(int(irq),
 					 procfs.hexbitmask(affinity, nr_cpus))
 
+	affinity = parse_irq_affinity_filename("default_smp_affinity", nr_cpus)
+	affinity = list(set(affinity + cpus))
+	set_irq_affinity_filename("default_smp_affinity", procfs.hexbitmask(affinity, nr_cpus))
+
 	return (previous_pid_affinities, previous_irq_affinities)
 
 def get_irq_users(irqs, irq, nics = None):