Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium


Linux device driver primer

Posted on 2003-03-11
Medium Priority
Last Modified: 2010-04-21

Could someone please explain in a topological way which *.c files are used when a write(), read() or open() is issued to a IDE device by a user-level program?

So far, I believe a write():
    |-?system call?
           |-<hardware level>

From my current researching, this is what I came up with, but wish that there is a explanation of this somewhere...

Question by:dvang_1
  • 4
  • 3

Expert Comment

ID: 8124890
You mean a read() system call?  Because there's also a read() function in the GNU C library.

But since you listed some kernel source files, I assume you mean the read() system call.  The first kernel module to run is the one whose source file is arch/i386/kernel/entry.S  (that's not a .c file, but it's what you want).  Of course, this assumes it's an i386 architecture machine.  The system call table there lists an address (sys_read) in the module whose source file is fs/read_write.c for the read() system call.  sys_read() then calls a routine in the device driver.  I don't know the ATA (IDE) device driver, but it looks like you have some familiarity with it.

The other system calls are pretty much the same.

There's no code in unistd.h or asm/unistd.h that executes in this scenario.

Author Comment

ID: 8132024
I'm a bit confused about the line:
>>You mean a read() system call?  Because there's also a read() function in the GNU C library.

When I do a man on read (2), it's says that I must include the <unistd.h> lib.  
Isn't this read() function more or less a system call?

I'm trying to understand how the read() function in C is tied to the block driver.  Or which path or paths must a read() take, in order to finally get to the kernel block driver function myblockdevice_read().

From what you've described, I'm at a lost where to look to find the file(s) that make the assignment that a particualar driver should be used, when a read() or write() is issued to a fd.

I quickly checked sys_read() in fs/read_write.c but could not find the relation ship to the block driver's myblockdevice_read() function.

-confucious :-)

Expert Comment

ID: 8137504
There is a connection between the read() system call and the read() C library function, but there is a fundamental difference between a system call and a library function.  A system call is a certain kind of interrupt that happens as a program runs, whereas a library function is just some bytes of code to which the program branches.

The connection is that the entire purpose of the read() function in the GNU C library is to cause the interrupt that is a read() system call.  The program branches to the read() function, the function executes an instruction to cause the interrupt, the interrupt handler eventually causes control to return to the read() function, and the read() function branches back to the code that called it.

The read() system call interface isn't documented; the read(2) man page is the documentation of the read() C library function.

>says that I must include the <unistd.h> lib

unistd.h is not a library.  It's an interface header file.  It doesn't contain any code that gets executed.  It just tells the compiler how to generate a call to the read() function.

>I'm at a lost where to look to find the file(s) that make
>the assignment that a particualar driver should be used,
>when a read() or write() is issued to a fd.

That's not easy to figure out from reading code because it is done by indirect calls.  One piece of code stores the address of a subroutine in storage and another piece of code reads that address and calls it.  Code that does that is always quite difficult to read.

You should see in sys_read() that it calls the read routine whose address is in the file pointer.  Every open file has a file pointer (struct file) and that file pointer contains the addresses of the subroutines that perform reads and writes and such on that file.  If the file is a device special file, those addresses are in a device driver.  The collection of subroutine addresses is called the file operations vector.

So what you want is the code that puts the file operations vector in the file pointer.  That's done when you open the file.  sys_open() calls filp_open(), which calls dentry_open(), which simply copies the file operations vector out of the inode.

So then the question becomes how does the file operations vector get into the inode?  The inode is created by the filesystem driver, so there's another indirect call that causes the driver for the particular filesystem type to get called.

If you want to make this a specific example, I can just tell you which routines run in that specific case.  Are you reading a regular file or a block device special file?  And what is the filesystem type of the filesystem in which that file resides?
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!


Author Comment

ID: 8141512
I appologize that I only have 75 points to give out, I just started using this service and it seems very promising.

I appreciate the prompt and knowledgable response.

I'm trying to learn the cmd640x driver for my own benefit and perhaps get good enough to start contributing to system drivers.  I have not found a good reference that'll teach from top level down of block device drivers as well as its scheduling, and queuing algorithms.

It's been a crash and burn, and crash and burn trip so far :-)

What you've described so far is a great insight so that I can start searching in the right places.  

If you have the time to explain in lay-terms to me :-), I am trying to get a feel of which routines are called from read() C library function call, all the way to the CMD64x.c kernel device driver.  I will be reading from a block device special file, no filesystem involved(I'm not dwelling into that yet ;-) ).  Pretty much raw access(I'm guessing that inodes will not play a role in this way?)




Author Comment

ID: 8141531
Forgot to mention that a CMD648-649 does not implement DMA correctly if at all, as complained from myself and many other users on the web.  

That is the main reason for me learning all of this.  I thought it'd be a great adventure.  I am a Comp Engr and for some reason, I feel I'm getting into alot of CSCI related work :-)

I understand or can understand the physical and link-level protocol of different buses, but this side project seems more involved than I thought.


Accepted Solution

bryanh earned 300 total points
ID: 8144162
Like any other file, the device special file has an inode while its in use.  The subroutine that runs when you do a read() system call is the routine whose address is in that inode.

We'll assume the device special file (e.g. /dev/hda) is in an ext2 filesystem.  In that case, the routine addresses were put into the inode by init_special_inode() in fs/devices.c.  That routine establishes the structure def_blk_fops as the file operations vector in the inode.  def_blk_fops is defined in fs/block_dev.c and indicates generic_file_read() in mm/filemap.c as the read routine.

And now we have another large gap between the read() system call and the device driver, because generic_file_read() reads through the buffer cache.  If the data isn't in the buffer cache, a conceptually separate part of the code has to read it from the device into the cache, and then generic_file_read() reads it from the cache.

To read the file, generic_file_read() calls the "readpage" routine for the file's cache.  A file cache is represented by a 'struct address_space' and contains a vector of operations that includes the "readpage" routine. In this case, that vector is a copy of 'def_blk_aops', which is in fs/block_dev.c. It specifies blkdev_readpage() as the "readpage" routine for the block device special file's cache.

blkdev_readpage() ultimately calls submit_bh() to submit the read operation to the block layer.  submit_bh() looks up the device special file's major number in a table of "request functions" and calls the indicated function to place the I/O request in a queue.  The device driver placed the address of its request function in that table when it initialized.  

I don't know the ATA driver, so I don't know what function that is in this case.  And I also don't know how it then steers the request to the proper controller driver when it takes it off the request queue.

Author Comment

ID: 8160211
Thanks Bryanh!

It'll take me some time to go through the "trace" that you've provided.  

Take care.


Featured Post

Get your Conversational Ransomware Defense e‑book

This e-book gives you an insight into the ransomware threat and reviews the fundamentals of top-notch ransomware preparedness and recovery. To help you protect yourself and your organization. The initial infection may be inevitable, so the best protection is to be fully prepared.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Have you ever been frustrated by having to click seven times in order to retrieve a small bit of information from the web, always the same seven clicks, scrolling down and down until you reach your target? When you know the benefits of the command l…
The purpose of this article is to fix the unknown display problem in Linux Mint operating system. After installing the OS if you see Display monitor is not recognized then we can install "MESA" utilities to fix this problem or we can install additio…
Loops Section Overview
Despite its rising prevalence in the business world, "the cloud" is still misunderstood. Some companies still believe common misconceptions about lack of security in cloud solutions and many misuses of cloud storage options still occur every day. …
Suggested Courses

581 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question