Pages

Formatting pen drive in command prompt

In older versions of linux distros the option to format pen drive or any hard disk is not available in the GUI. Or in case you are stuck in the text mode and want to format a disk , here is a way out.

The command "mkfs" and its variants are meant to create a  filesystem on a disk. There are various "mkfs" commands depending on what file system you want to create on the disk. The most commonly used are
mkfs.ext2, mkfs.ext3, mkfs.vfat  where they are used to create ext2,ext3 and FAT file system on the disk respectively.

If you want to use your disk with windows too then it is recommended to use "mkfs.vfat" as windows can not recognize ext filesystem.
To format the disk, plug it into the system.
Open a terminal and run the command
$ df -h
Example output
/dev/sda1              46G   10G   34G  23% /
/dev/sdb1             1.9G  694M  1.2G  37% /media/NS

External disks are listed under /media, hence from the above output we can figure out that the partition to be formatted  is "/dev/sdb1" which is listed in the first column of the corresponding disk.

Now run the following to format the disk 
NOTE: All data in the disk be lost and can not be recovered.

$ umount /dev/sdb1
$ sudo mkfs.vfat /dev/sdb1


That is it, your disk should be formatted and clean now.

Reader Writer Semaphores in Linux

In the last post, Semaphores in linux, we saw the use of semaphores in linux. Semaphores are used to restrict the access to the shared resources.
When the shared resource is only read and not written to, there is no change to the data and hence if multiple processes want to only read from the shared resource there should not be any problem in allowing access to all readers.
Linux provides a special kind of semaphore, reader/writer semaphore,that allows multiple readers into the critical section but only one writer at any given time.
The structure used for the semaphore is "struct rw_semaphore"

Initializing the semaphore :
void init_rwsem(struct rw_semaphore

To hold the semaphore for reading we can use one of the following

void down_read(struct rw_semaphore *sem) : sleeps if semaphore is not available.
int down_read_trylock(struct rw_semaphore *sem):  Returns with an error if semaphore is not available.

Releasing a semaphore held for reading :

void up_read(struct rw_semaphore *sem);

To hold a semaphore for writing :

void down_write(struct rw_semaphore *sem) : sleeps if semaphore is not available.
int down_write_trylock(struct rw_semaphore *sem):  Returns with an error if semaphore is not available.

Releasing a semaphore held for reading :

void up_write(struct rw_semaphore *sem);

Let us look at an example to understand the working.
We make use of the basic character driver written from "Writing an example driver from scratch"  .

Every time we enter the read function a read/write semaphore is held and a message is printed to indicate that the semaphore was held successfully.
In the write function too we try to hold the same read/write semaphore but now write, we will see that if there are processes reading from the device the read is put to sleep but any number of readers are allowed at a time.

*******************************rw_sema.c******************************
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h> // required for various structures related to files liked fops.
#include <asm/uaccess.h> // required for copy_from and copy_to user functions
#include <linux/semaphore.h>
#include <linux/cdev.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/time.h>

wait_queue_head_t queue;
static int Major;
char flag='n';
struct task_struct *task;

struct device {
    char array[100];
    struct rw_semaphore rwsem;
}char_arr;

int open(struct inode *inode, struct file *filp)
{
   
    printk(KERN_INFO "Inside open \n");
    task = current;

    return 0;
}

int release(struct inode *inode, struct file *filp) {
    printk (KERN_INFO "Inside close \n");
    return 0;
}

ssize_t read(struct file *filp, char *buff, size_t count, loff_t *offp) {
    unsigned long ret;
    down_read(&char_arr.rwsem);
    printk("Inside read \n");
    ret = copy_to_user(buff, char_arr.array, count);
    wait_event_timeout(queue,flag!='n',30*HZ);
    up_read(&char_arr.rwsem);
    return ret;
}

ssize_t write(struct file *filp, const char *buff, size_t count, loff_t *offp) {   
    unsigned long ret;
    down_write(&char_arr.rwsem);
    printk(KERN_INFO "Inside write \n");
    ret =    copy_from_user(char_arr.array, buff, count);
    up_write(&char_arr.rwsem);
    return ret;
}


struct file_operations fops = {
    read:        read,
    write:        write,
    open:         open,
    release:    release
};


struct cdev *kernel_cdev;


int char_arr_init (void) {
    int ret;
    dev_t dev_no,dev;

    kernel_cdev = cdev_alloc();   
     kernel_cdev->ops = &fops;
    kernel_cdev->owner = THIS_MODULE;
    printk (" Inside init module\n");
     ret = alloc_chrdev_region( &dev_no , 0, 1,"chr_arr_dev");
    if (ret < 0) {
        printk("Major number allocation is failed\n");
        return ret;   
    }
   
    Major = MAJOR(dev_no);
    dev = MKDEV(Major,0);

    printk (" The major number for your device is %d\n", Major);
    ret = cdev_add( kernel_cdev,dev,1);
    if(ret < 0 )
    {
    printk(KERN_INFO "Unable to allocate cdev");
    return ret;
    }
    init_rwsem(&char_arr.rwsem);
    init_waitqueue_head(&queue);
   
    return 0;
}

void char_arr_cleanup(void) {
    printk(KERN_INFO " Inside cleanup_module\n");
    cdev_del(kernel_cdev);
    unregister_chrdev_region(Major, 1);
}
MODULE_LICENSE("GPL");   
module_init(char_arr_init);
module_exit(char_arr_cleanup);
*******************************************************************
*********************************Makefile*************************
ifneq ($(KERNELRELEASE),)
   obj-m := rw_sem.o
else

KERNELDIR ?= /lib/modules/$(shell uname -r)/build

PWD := $(shell pwd)

default:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules 
endif
clean:
    $(MAKE) -C $(KERNELDIR)  M=$(PWD) clean
************************************************************************

User applicatoin:

*****************************user_app.c*********************************

#include <stdio.h>
#include <fcntl.h>


main ( ) {
        int i,fd;
        char ch, write_buf[100], read_buf[100];

        fd = open("/dev/temp", O_RDWR);

        if (fd == -1)
        {
                printf("Error in opening file \n");
                exit(-1);
        }
        printf ("Press r to read from device or w to write the device ");
        scanf ("%c", &ch); 


        switch (ch) {
                case 'w':
                       printf (" Enter the data to be written into device");
                        scanf (" %[^\n]", write_buf);
                        write(fd, write_buf, sizeof(write_buf));
                        break;
                case 'r':

                        read(fd, read_buf, sizeof(read_buf));
                        printf ("The data in the device is %s\n", read_buf);
                        break;

                default:
                        printf("Wrong choice \n");
                        break;
        }
        close(fd);
}



*******************************************************************




To see the output run the following commands

$ make
$ sudo insmod rw_sem.ko
$ cat /proc/devices | grep char_arr_dev
250 char_arr_dev    (Note the number might be different in your system.)

$ sudo mknod /dev/temp c 250 0
$ cc user_app.c
Now open 4 separate terminals

One terminal :
$sudo ./a.out 
Press r to read from device or w to write the device r   (Note press "r")



Second terminal
$sudo ./a.out 
Press r to read from device or w to write the device r   (Note press "r")

Third terminal
$sudo ./a.out 
Press r to read from device or w to write the device r   (Note press "w")

In the fourth terminal
$ dmesg
 Inside open  //open by first read
 Inside read  //  Entered read after holding semaphore
 Inside open  // Open by second read
 Inside read // Entered read after holding the same semaphore so two readers are present now                                            
 Inside open // Open by the write which is put to sleep when it tries to hold the semaphore.

Wait for a while till the two readers exit.

Now run dmesg again
$ dmesg

Inside close   // Close by first read
Inside close  // Close by first read
Inside write  //Writer is allowed to enter after both readers exit.

 




Using Semaphores in Linux

Semaphore as used in an operating system to restrict the access to resources by multiple processes at the same time. When a semaphore is used to restrict the access to only one process at a time, it is termed as mutex, as it serves the purpose of mutual exclusion.
The part of the program which accesses the shared resource is called as the critical section. Hence a semaphore restricts the execution of the critical section by multiple processes at the same time.

Traditionally semaphores have two functions associated with it, called "P" and "V" .
Every process before entering a critical section calls the function "P", if no other process is executing the critical section the semaphore is held by the process and the process is allowed to enter the critical section.
In case the semaphore is already held by some other process, that is some other process is executing the critical section, then "P" puts the current process to sleep.
The function "V" on the other hand releases the semaphore that is being held by the process.

In linux the equivalent calls for P and V are down() and up() respectively.

When a process calls down() the value of the semaphore is decremented and if value after decrementing is zero or greater than zero the process is allowed to enter the critical section. But on the other hand if the new value is negative then the process is put to sleep on a wait queue. 
On the other hand when a process calls up() the value of the semaphore is incremented by one.

When we want to use the semaphore as a mutex, the value of semaphore is initialized to 1. So at any give time only one process can execute the critical section.


To make use of a semaphore we need the header file <asm/semaphore.h>  and variable is of the type "struct semaphore".

Semaphore initialization:

struct semaphore name;
sema_init(&name, count);


More often than not semaphore is used as a mutex during module programming, hence kernel developers have provided a separate function calls to initialize a semaphore as a mutex.

static DECLARE_MUTEX(name);

To create it dynamically we can use
 
init_MUTEX(name);

Various kinds of down() :

down() : Will keep waiting for the semaphore unless it does not become available. Can not be interrupted.
down_interruptible(): Will keep waiting for the semaphore unless it does not become available but can be interrupted. This is always preferable over down().
down_trylock() : Will not put the process to sleep if semaphore is already being held, but returns immediately with non zero return value.

There are no variations of up().

Let us look at an example module to understand the working of semaphore better.
The module below is a character driver to control a virtual device that we create using an array.You can refer to "Writing a driver from scratch " for further details.
In the module we create two proc entries "hold" and "remove"
When "hold" is read it locks a semaphore and when "remove" is read it unlocks the same semaphore.

The same semaphore is also held when a user space application tries to access  the device. Hence to understand the working of semaphore we will lock the semaphore by reading "hold" first and then try to access the device, which should put the process to sleep until we call read on remove and release the semaphore.

***************************sema.c**********************************************
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h> // required for various structures related to files liked fops.
#include <asm/uaccess.h> // required for copy_from and copy_to user functions
#include <linux/semaphore.h>
#include <linux/cdev.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>


static int Major;
char flag='y';
struct task_struct *task;
struct device {
    char array[100];
    struct semaphore sem;
}char_arr;

int open(struct inode *inode, struct file *filp)
{
   
    printk(KERN_INFO "Inside open \n");
    task = current;                 // Saving the task_struct for future use.
    if(down_interruptible(&char_arr.sem)) {
        printk(KERN_INFO " could not hold semaphore");
        return -1;
    }
    return 0;
}

int release(struct inode *inode, struct file *filp) {
    printk (KERN_INFO "Inside close \n");
    printk(KERN_INFO "Releasing semaphore");
    up(&char_arr.sem);
    return 0;
}

ssize_t read(struct file *filp, char *buff, size_t count, loff_t *offp) {
    unsigned long ret;
    printk("Inside read \n");
    ret = copy_to_user(buff, char_arr.array, count);
    return ret;
}

ssize_t write(struct file *filp, const char *buff, size_t count, loff_t *offp) {   
    unsigned long ret;
    printk(KERN_INFO "Inside write \n");
    ret =    copy_from_user(char_arr.array, buff, count);
    return ret;
}
int hold(char *buf,char **start,off_t offset,int count,int *eof,void *data )
{
int len=0;
down_interruptible(&char_arr.sem);   // holding the semaphore
printk(KERN_INFO "Inside hold");
return len;
}

int remove(char *buf,char **start ,off_t offset,int count,int *eof,void *data )
{
int len=0;
/* according to linux/sched.h the value of state and their meanings are
-1 unrunnable, 0 runnable, >0 stopped*/

printk(KERN_INFO "State before= %i", task->state);  // printing the state of user process
up(&char_arr.sem);
printk(KERN_INFO "Inside remove");
printk(KERN_INFO "State after = %i", task->state); // printing the state of user process

return len;
}


void create_new_proc_entry()
{
create_proc_read_entry("hold",0,NULL,hold,NULL);
create_proc_read_entry("remove",0,NULL,remove,NULL);
}

struct file_operations fops = {
    read:        read,
    write:        write,
    open:         open,
    release:    release
};


struct cdev *kernel_cdev;


int char_arr_init (void) {
    int ret;
    dev_t dev_no,dev;

    kernel_cdev = cdev_alloc();   
     kernel_cdev->ops = &fops;
    kernel_cdev->owner = THIS_MODULE;
    printk (" Inside init module\n");
     ret = alloc_chrdev_region( &dev_no , 0, 1,"chr_arr_dev");
    if (ret < 0) {
        printk("Major number allocation is failed\n");
        return ret;   
    }
   
    Major = MAJOR(dev_no);
    dev = MKDEV(Major,0);

    printk (" The major number for your device is %d\n", Major);
    ret = cdev_add( kernel_cdev,dev,1);
    if(ret < 0 )
    {
    printk(KERN_INFO "Unable to allocate cdev");
    return ret;
    }
    init_MUTEX(&char_arr.sem);

    create_new_proc_entry();
    return 0;
}

void char_arr_cleanup(void) {
    printk(KERN_INFO " Inside cleanup_module\n");
    remove_proc_entry("hold",NULL);
    remove_proc_entry("remove",NULL);
    cdev_del(kernel_cdev);
    unregister_chrdev_region(Major, 1);
}
MODULE_LICENSE("GPL");   
module_init(char_arr_init);
module_exit(char_arr_cleanup);
******************************************************************************

************************Makefile******************************************
ifneq ($(KERNELRELEASE),)
   obj-m := sema.o
else

KERNELDIR ?= /lib/modules/$(shell uname -r)/build

PWD := $(shell pwd)

default:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules 
endif
clean:
    $(MAKE) -C $(KERNELDIR)  M=$(PWD) clean
************************************************************************

User application to access the device

********************user_app.c************************************
#include <stdio.h>
#include <fcntl.h>


main ( ) {
        int i,fd;
        char ch, write_buf[100], read_buf[100];

        fd = open("/dev/temp", O_RDWR);

        if (fd == -1)
        {
                printf("Error in opening file \n");
                exit(-1);
        }
        printf ("Press r to read from device or w to write the device ");
        scanf ("%c", &ch); 


        switch (ch) {
                case 'w':
                       printf (" Enter the data to be written into device");
                        scanf (" %[^\n]", write_buf);
                        write(fd, write_buf, sizeof(write_buf));
                        break;
                case 'r':

                        read(fd, read_buf, sizeof(read_buf));
                        printf ("The data in the device is %s\n", read_buf);
                        break;

                default:
                        printf("Wrong choice \n");
                        break;
        }
        close(fd);
}


***********************************************************************************




To see the functioning run the above code as follows

$ make
$ sudo insmod sema.ko
$ dmesg

/*You should see the major number allocated to the driver in the output of dmesg, we assume it is 250*/
$ sudo mknod /dev/temp c 250 0
$  cc use_semaphore.c
$  cat /proc/hold
$  sudo ./a.out

 /* The process should go to sleep now,as it is waiting for the semaphore to be released.
Open a new terminal and run the following command*?
$ cat /proc/remove
/*Now go back to the previous terminal, you should see the process should have waken up and entered the case statement in the code i.e. */
Press r to read from device or w to write the device

/* If you execute dmesg now you should see the state of the user_app being printed when remove  proc entry was read.
State before= 1 and
State after = 0
The state 1 means the process was stopped, that was when the process was waiting for the semaphore. After the semaphore is released the state change to "0" which means the process is running.*/