Archive for May, 2008

Interview with Jon Masters

Tuxology team May 22nd, 2008

Linux.com’s Robin ‘Roblimo’ Miller interviews Jon Masters, Linux kernel hacker, RedHat device drivers maintainer and author of several Linux books, during Linux Foundation Collaboration Summit of 2008 about drivers back porting and other issues.

Browsing the PCI bus

Gilad Ben-Yossef May 20th, 2008

Another letter from one of our students, this time from Ami Givati from Intel:

Hello Gilad,

Knowing your Linux expertise (from Intel Network training last month, and a Linux debug class), I think you should be able to help me with this:

I am looking for a Linux tool which will allow me to browse the PCI (and mainly PCI Express) hierarchy. I need to view the hierarchy tree, and to read and modify values in the PCI Config space of various devices. A GUI tool is preferred, but also a command line would be of value. Are you familiar with such a tool?

Appreciate your help…

Well Ami, the answer is easier then you might think - you can simply use one of the Linux shells.

You see, Linux exposes the PCI (actually all hardware buses) hierarchy as simple files and directories udner the sysfs virtual file system and let you access them simply from the shell.

Of course, you can easily wrap a GUI around it but access via the Linux shell is easy enough, for example:

gby@voyager:~$ cd /sys/
gby@voyager:/sys$ cd devices/
gby@voyager:/sys/devices$ ls
acpi_system:00  pci0000:00  platform  pnp0  system
gby@voyager:/sys/devices$ cd pci0000\:00/
gby@voyager:/sys/devices/pci0000:00$ ls
0000:00:00.0  0000:00:1a.1  0000:00:1c.2  0000:00:1d.2  0000:00:1f.3
0000:00:02.0  0000:00:1a.7  0000:00:1c.3  0000:00:1d.7  power
0000:00:02.1  0000:00:1b.0  0000:00:1c.4  0000:00:1e.0  uevent
0000:00:19.0  0000:00:1c.0  0000:00:1d.0  0000:00:1f.0
0000:00:1a.0  0000:00:1c.1  0000:00:1d.1  0000:00:1f.2
gby@voyager:/sys/devices/pci0000:00$ cd 0000:00:1d.0
gby@voyager:/sys/devices/pci0000:00/0000:00:1d.0$ ls
broken_parity_status  enable      pools             subsystem_vendor
bus                   irq         power             uevent
class                 local_cpus  resource          usb3
config                modalias    resource4         usb_host:usb_host3
device                msi_bus     subsystem         vendor
driver                numa_node   subsystem_device
gby@voyager:/sys/devices/pci0000:00/0000:00:1d.0$ hexdump config
0000000 8086 2830 0005 0280 0003 0c03 0000 0080
0000010 0000 0000 0000 0000 0000 0000 0000 0000
0000020 18a1 0000 0000 0000 0000 0000 17aa 20aa
0000030 0000 0000 0000 0000 0000 0000 010a 0000
0000040

For more details about the PCI sections of sysfs, check out the sysfs-pci.txt file in the Linux documentation.

And anyone else has a question, don’t hesitate to let us know.

Hope this helps,
Gilad

Reducing the size of dynamic libraries

Gilad Ben-Yossef May 15th, 2008

Today we have a special reader request from an anonymous reader (slightly edited):


Hello,

Can you help me with some link issue which I face?

I need to compile tree of c-sources which produce .so files and exe
files. I want to decrease the sizes of .so by throwing away unused symbols.

I can compile my tree statically and used as compiler flags –static -ffunction-sections -fdata-sections and link with –gc-sections option and it reduces all the unneeded symbols but I want to achieve the same effect in dynamic linking.

Do you know some efficient way to do it?

Thanks,
Anonymous Reader

So the question is: how to make a minimal set of dynamic libraries for a known set of executables that only contain the code for those symbols which the executables actually use, thus saving expensive storage?

The quite simple answer is that there exists a Python utility that does exactly what you want called mklibs - It produces cut-down shared libraries that contain only the routines required by a particular set of executables.

On Debian just go “sudo apt-get install mklibs”, or you can get the source straight from the Buildroot source repository here.

If you don’t like Python (you really should!) you can try an older, shell script based variation on the same theme found here.

Note that you can pass the cross compiler prefix with the “–target” option, which is of course needed for supporting cross compilation.

Hope you found it useful and if you have more questions about Linux development you’d like answered, just let us know.

This post originally appeared in the Codefidence Technoblog

Using a shared library constructor

Gilad Ben-Yossef May 15th, 2008

Shared libraries, sometime also referred to as DSO (for Dynamic Shared Objects) or DLL (for Dynamically Loadable Modules), offer an easy way to pack together useful functions and data as a code library that can be easily reused, updated separately from all the application making use of it and most important - under certain conditions allows most the code and data of the library to only be loaded once to the machine RAM regardless of the number of applications using it.

A shared library is thus normally comprised of a set of global functions which may be called by applications (or other libraries) that link with the library.

Given the shared nature of shared libraries, it is often useful to provide a constructor for the code library which will run each time the library is loaded by an application. Doing this is very simple, using the GNU specific constructor attribute.

Here is a code example:

 
/* init_demo.c */
 
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
 
static void __attribute__ ((constructor)) \
  lib_init(void);
 
static void lib_init(void) {
 
  printf("Library ready. \n");
 
  return;
}

Then build the the shared library using the following GNU Makefile:

 
.PHONY: clean
 
libinitdemo.so.1.0.0: init_demo.c 
  $(CC) -fPIC init_demo.c -shared \
  -Wl,-soname,libinitdemo.so.1 -o \
  libinitdemo.so.1.0.0
 
clean:
  $(RM) -f libinitdemo.so.1.0.0

TIP
Combining a shared library constructor as shown above with use of LD_PRELOAD can be a powerful way to add construction code to existing programs without changing their source code and indeed, without requiring access to their source code at all.

This post originally appeared in the Codefidence Technoblog

Forcing connections through a specific interface

Gilad Ben-Yossef May 15th, 2008

It can sometime be very useful to force an application to force to use a specific network interface for routing traffic, the regular routing tables not withstanding.

An example for such cases is where an embedded Linux system has a management network interface and a separate regular network interface where regular traffic should go:

So long as the two interfaces use two different IP addresses from non overlapping network it is very easy - simply bind the management application socket to the management IP and let the routing table do the rest.

What to do, however, if product definition calls for supporting two different and separate, default gateway settings for management and media traffic? Although we can assign multiple default gateway routing table entries, how to make sure the management applications use one and all other traffic use another?

This is where the SO_BINDTODEVICE socket option comes to our rescue. We will install two default gateway entries: a normal one for the media traffic and another one for the management traffic, for which we will define a high metric so it will normally will not be used.

Then, we will set the SO_BINDTODEVICE socket option on sockets opened in management application, thus forcing the Linux networking stack to disregard any routing table entries not going through the specific device, but only for those specific sockets.

It looks something like this:

#include <sys/socket.h>
#include <net/if.h>
struct ifreq interface;
struct socket sock;
/* Management net interface name */
#define IFNAME "eth3"
 
/* Acquire socket here ... */
 
strncpy(interface.ifr_ifrn.ifrn_name, IFNAME, \
  IFNAMSIZ);
if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, \
  (char *)&interface, sizeof(interface))  < 0) {
       perror("SO_BINDTODEVICE failed");
      /* Deal with error... */
}

But wait! this is all well and good when we have the management application source code. This however is not always the case. Fear not! this too can be dealt with by hijacking the socket library call:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#define __USE_GNU // Get RTLD_NEXT definition
#include <dlfcn.h>
 
/* Management interface */
#define IFNAME "eth3"
 
int socket(int domain, int type, int protocol) {
 
int (*origsock)(int domain, int type, int protocol);
char * error;
int sock;
 
origsock = dlsym(RTLD_NEXT, "socket");
if ((error = dlerror()) != NULL) {
fprintf (stderr, "%s\n", error);
exit(1);
}
 
sock = origsock(domain, type, protocol);
if(sock != -1) {
  struct ifreq interface;
  strncpy(interface.ifr_ifrn.ifrn_name, IFNAME, \
  IFNAMSIZ);
  if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, \
    (char *)&interface, sizeof(interface)) < 0) {
      perror("sendpacket: setting SO_BINDTODEVICE");
      exit(1);
   }
}
 
return sock;
}

Compile this small library with (or create a proper Makefile)

$ gcc sendto.c -fPIC -o sendto.so -ldl -shared

To use:

LD_PRELOAD=sendto.so ./management_app

This post originally appeared in the Codefidence Technoblog

Kernel panic messages

Gilad Ben-Yossef May 15th, 2008

It is sometime useful to be able to store the text of kernel panic messages in non volatile memory for postmortem fault analysis, in lieu of big enough storage device or network medium to store or send these message in the field.

The following code examples shows how this can be accomplished.

Some notes and caveats are due: the code does not deal with initializing the non volatile memory, if applicable. To use this example with NOR flash, as an example, code handling flash erasing will need to be added. In addition, this example does not display or clear saved messages and implementing this is left as an exercise to the reader.

Here is the Makefile:

default:
   $(MAKE) -C /lib/modules/`uname -r`/build \
      SUBDIRS=`pwd` modules
 
clean:
  $(MAKE) -C /lib/modules/`uname -r`/build \
      SUBDIRS=`pwd` clean

The simple Kbuild file is:

obj-m := panic_msg.o

And the panic_msg.c is:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/notifier.h>
#include <linux/ioport.h>
#include <asm/io.h>
 
#define LOG_PREFIX "panic_msg: "
 
static unsigned long buf_address = 0;
module_param(buf_address, ulong, S_IRUSR);
MODULE_PARM_DESC(buf_address, 
  "The physical address of the panic message buffer.");
 
static unsigned long buf_size = 0;
module_param(buf_size, ulong, S_IRUSR);
MODULE_PARM_DESC(buf_size, 
  "The size in bytes of the panic message buffer.");
 
static unsigned int notifier_priority = INT_MAX;
module_param(notifier_priority, uint, S_IRUSR);
MODULE_PARM_DESC(notifier_priority, 
  "Notifier priority: INT_MAX &gt;= x &gt;= 0.");
 
static char * buf;
 
static int panic_msg_handler(
  struct notifier_block *this, 
  unsigned long event,void *msg)
{
  static unsigned int panic_event_handled = 0;
  unsigned int msg_size = min(strlen(msg), buf_size);
 
  if(!panic_event_handled) {
     panic_event_handled = 1;
     memcpy_toio((char *)msg, buf, msg_size);
  }
  return NOTIFY_OK;
}
 
static struct notifier_block panic_msg_notifier = {
  .notifier_call  = panic_msg_handler,
  .next           = NULL,
  .priority       = INT_MAX
};
 
static int __init panic_msg_init(void)
{
  int ret = 0;
  struct resource * res = NULL;
 
  if((!buf_address) || (!buf_size)) {
    printk(KERN_ERR LOG_PREFIX 
      "Address and size parameters are mandatory.\n", 
      buf_address, buf_size);
    ret = -EINVAL;
    goto error;
  }
 
  panic_msg_notifier.priority = notifier_priority;
 
  res = request_mem_region(buf_address, buf_size, 
    "Panic message handler");
 
  if(!res) {
    printk(KERN_ERR LOG_PREFIX 
      "Failed requesting panic message buffer " \
      "at address  0x%lx of size %ld.\n",
      buf_address, buf_size);
    ret = -EINVAL;
    goto error;
  }
 
  buf = ioremap(buf_address, buf_size);
 
  if(!buf) {
    printk(KERN_ERR LOG_PREFIX 
      "Failed mapping panic msg buf at address" \
      " 0x%lx of size %ld\n", 
      buf_address, buf_size);
    ret = -EINVAL;
    goto error;
  }
 
  if(atomic_notifier_chain_register(
     &panic_notifier_list, &panic_msg_notifier)) {
    printk(KERN_ERR LOG_PREFIX 
      "Failed registering panic message notifier.\n");
    ret = -EINVAL;
    goto error;
  }
 
  printk(KERN_INFO LOG_PREFIX 
   "Panic message buffer handler initialized.\n");
 
  return 0;
 
error:
  if(res) release_mem_region(buf_address, buf_size);
  if(buf) iounmap(buf);
  return ret;
}
 
static void __exit panic_msg_exit(void) {
 
  if(atomic_notifier_chain_unregister(
     &panic_notifier_list, &panic_msg_notifier)) {
    printk(KERN_ERR LOG_PREFIX 
      "Failed removing panic msg buf mapping.\n");
  }
  iounmap(buf);
  release_mem_region(buf_address, buf_size);
 
  printk(KERN_INFO LOG_PREFIX 
     "Panic message buffer handler unloaded.\n");
 
  return;
}
 
module_init(panic_msg_init);
module_exit(panic_msg_exit);
 
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Gilad Ben-Yossef" \
  " <gilad@codefidence.com>");
MODULE_DESCRIPTION("This module stores kernel  " \
   "panic messages in non volatile memory.");

Panic message example kernel module source code

This post originally appeared in the Codefidence Technoblog

Dynamic Linker Demystefied

Tuxology team May 15th, 2008

Slides for the presentation on the Linux dynamic linker given by Gilad Ben-Yossef, Codefidence CTO, at the Wind River Embedded Linux Conference in Ramat Ilan, Israel in December 4, 2007 has been published on the Codefidence web site.

Setting tasks CPU affinity

Gilad Ben-Yossef May 15th, 2008

Linux kernel 2.6 and latest versions of 2.4 support two system calls that allow one to limit processes to specific CPUs.

The system calls are:

#include <sched.h>
 
int sched_setaffinity(pid_t  pid, unsigned int len, unsigned long *mask);
 
int sched_getaffinity(pid_t pid, unsigned int len, unsigned long *mask);

pid is the process id of the process to assign to certain CPUs. Use ‘0′ here to denote the current process.

len is the length of the CPU bit mask, and mask is a pointer to a bit mask denoting which CPU can the process run on.

For a good discussion and a code example, look here:

http://www-128.ibm.com/developerworks/linux/library/l-affinity.html

This post originally appeared in the Codefidence Technoblog

Using proccess specific APIs on threads

Gilad Ben-Yossef May 15th, 2008

A lot of POSIX API’s require a PID, or process ID, as a parameter. Sometime it is useful to use such an API on a thread, rather then a process.

Since Linux internally implements all processes and threads as tasks, one can use the Linux specific gettid(2) system call to get the “Thread ID” of a thread, which is really equal to a process PID, at least so much as to be useful as a parameter for a POSIX system call that requires a PID.

The use is Linux specific, non portable and it is not clear if it is a stable API or an undocumented coincidence. Use with care.

This post originally appeared in the Codefidence Technoblog

Determining PThread Library Type

Gilad Ben-Yossef May 15th, 2008

Linux kernel versions prior to 2.6 did not offer good internal support for threads. Therefore a threading library called LinuxThreads was used to provide most of the POSIX PThread API.

Since Linux 2.6 good threading support was added to the Linux kernel and a new library, called NPTL for New Posix Threading Library was created to provide scalable, robust POSIX compliant threading support in Linux.

As both libraries use the same POSIX API, code written for one will usually work with the other as is, but not always. It is therefore some time desirable to be able to learn in run time which threading library is being used.

The following code example shows how this can be done:

#define _XOPEN_SOURCE
#include <unistd.h>
#include <stdio.h>
 
int main(void)
{
char name[128];
confstr (_CS_GNU_LIBPTHREAD_VERSION, 
  name, sizeof(name));
printf ("Pthreads lib: %s\n", name);
return 0;
}

This post originally appeared in the Codefidence Technoblog

Next »