Skip to content

Commit

Permalink
Add module code and update README
Browse files Browse the repository at this point in the history
  • Loading branch information
rikyoz committed Nov 1, 2018
1 parent 1f23a0f commit 2bbeb7e
Show file tree
Hide file tree
Showing 10 changed files with 961 additions and 2 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,5 @@ modules.order
Module.symvers
Mkfile.old
dkms.conf

*.pdf
12 changes: 12 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
CONFIG_MODULE_SIG=n
WARN := -W -Wall -Wstrict-prototypes -Wmissing-prototypes
ccflags-y := -O2

obj-m += mailslot.o
mailslot-objs := ./src/mailslot_driver.o ./src/mailslot.o

all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
73 changes: 71 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,71 @@
# LinuxMailslotsModule
Windows mailslots for the Linux kernel
<h1 align="center">
Linux Mailslots Module
</h1>

<h3 align="center">Windows mailslots for the Linux kernel</h3>

<p align="center">
<a href="https://github.com/rikyoz/LinuxMailslotsModule/releases/latest"><img src="https://img.shields.io/github/release/rikyoz/LinuxMailslotsModule/all.svg?style=flat-square&logo=github&logoColor=white&colorB=blue" alt="GitHub release"></a>
<img src="https://img.shields.io/badge/OS-Linux-red.svg?style=flat-square&logo=linux&logoColor=white" alt="MSVC version">
<img src="https://img.shields.io/badge/arch-x86,%20x86__64-orange.svg?style=flat-square&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAQAAAAAYLlVAAAC1UlEQVR42u3WA9AjWRSA0bu2bdu2bdssrm3btm3btm3bmX+Ms7rLTiW9NUmvcsL7XuELu6Ojoz5DWcc5nvKp2kBdPvesi21m1Pgr7OxjrfWtgw0VZZjKM9rjXfNHM+bWWzutGo2YSH/tNm+jgNe1XzdDR322V41Tox5D6K4qY0WRtVRnjyhysercH0VeVJ13o8hXqvNNFOlSna4oUlOd2r8moBPwoQfd6THfoLweauqp6aJ8wInmMmjujWAFtwMeNJup5cXsVnWYDyDtajQjmMp7QOoypxGMbMtyAe+Ztf5/JTaJAkM6mjRXrj0KpE9zdZIyAV8bLX5lBIPlszXAVlGXMwAr5fwskL4wdPzAfGUC5o9kJy+o+dCVloiwJNg2907wimddZrqcB9GtNQF3RXI+kI5yCcgADwF6yvfLNa0JWD7n5dWXAa4lbZwrR7UioKdhc76vdEB+KxzbioAncxpGr9IBM+XKDa0IuCanaWkS8BzguEhqrQg4P6e5mgasbV+7WCySvWlFwIU5zdYooMhytCbghpzGLh9gAodCWjFXXwDSV4aJH5inWcBLkbzTOMBa9rWvk92jH5BWqBvwjSHKBfQ3as4HlvoSFq2b+zcB6bXIj6pZABvnPKzPgPSJlxV/hkUH5v7SUPiv2LN5wKuRjO82wDdON6xFSwW8XvhdcGYkrzUPYJf4lcktZh4jxg8sViqA9SKZxDo2NH0km1ImgE2jDjuBLXK6FPX1N1fUYQnKBnCeGeN3jGdPfUC+P27TyO7GjN8xoUMpHZCecKZ97etE9+hD6vKQOz1jgMa6u90J+VO9V//OaXnzgE5Al+p0iyLfqM63UeRV1Xk/ilylOo9Gkc1U55AoMrz+qjJJ1OMQ1bgq6jOYr1Rh9EgFZtd+q0QjVtFeW0UzFvGJ9uhhrSjDSE7UX6tdaMIoz0R2cbvXfKE2UJevvOEe+5kuOjr+qb4H0/HV/SQ0YjEAAAAASUVORK5CYII=" alt="Architectures">
<a href="https://github.com/rikyoz/bit7z/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-GNU%20GPL%20v2-lightgrey.svg?style=flat-square&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAQAAAAAYLlVAAAAvUlEQVR42u3Zt1EEURRE0Ye0gFwI4BWJoC0KGxftExk+RQATAN+nLpo1R0+v6NsJHPOLcO4vKkrPVexEcMFZN8AQ7UXwCBx0ART6VtiN4BCA1AHO+SnVAEg1AFINgFQDINUASDUAUg2AVAMg1QBINQBSDYBUAyDVAMhxAVfUdzkmYJ+7mj1xPQ7gjbWYJTmQbGsB77zy0mjPPQH9UwOKAQYYYIABBhhggAFzCTDAAAMMMGDS+v2a9V8Vzs1PH+dRolvEzoAoAAAAAElFTkSuQmCC" alt="License"></a>
</p>
<p align="center">
<a href="#features">Features</a> •
<a href="#building">Building</a> •
<a href="#usage">Usage</a> •
<a href="#license-gpl-v2">License</a>
</p>

This project provides a simple and easy to use Linux kernel module implementing a service similar to Windows mailslots, i.e. a driver for special device files accessible according to FIFO policy.

Developed for the course of *Advanced Operating Systems and Virtualization* (AOSV) taken in the A.Y. 2016/2017 for the *Master Degree in Engineering in Computer Science* (MSE-CS) at *Sapienza University of Rome*.
The original project specification can be found [here](https://www.dis.uniroma1.it/~quaglia/DIDATTICA/AOSV/examination.html).

## Features
The module is a Linux driver for special device files supporting the following features:

+ **FIFO** (**F**irst **I**n **F**irst **O**ut) access policy semantic (via *open/close/read/write* services).
+ **Atomic** message read/write, i.e. any segment read from or written to the file stream is seen as an independent data unit, a message, and it is posted/delivered atomically (all or nothing).
+ Support to **multiple instances** accessible concurrently by active processes/threads.
+ **Blocking/Non-Blocking** runtime behaviour of I/O sessions (tunable via *open* or *ioctl* commands)
+ Runtime configuration (via ioctl) of the following parameters:
+ *Maximum message size* (configurable up to an absolute upper limit).
+ *Maximum mailslot storage size* which is dynamically reserved to any individual mailslot.
+ Compile-time configuration of the following parameters:
+ *Range of device file minor numbers* supported by the driver (default: [0-255]).
+ *Number of mailslot instances* (default: 256).

## Building

The project provides a Makefile and can be compiled using the `make` command line utility.

## Usage

Once built, the module can be manually installed using the `insmod mailslot.ko` command (or via the `install.sh` utility shell script, which installs the module and creates also 3 mailslots files in the `/dev/` directory).
Mailslot files can be created using the `mknod` command (for example usages, please see the `install.sh` script),

In order to uninstall the module, the `rmmod mailslot` command must be used, as well as mailslot files can removed using the `rm` command (if the installation script was used, the module can also be uninstalled using the provided `uninstall.sh` shell script, which removes also the 3 mailslots files created during the installation).

## License (GPL v2)

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

<br/>
<div align="center">

Copyright &copy; 2017 - 2018 Riccardo Ostani ([@rikyoz](https://github.com/rikyoz))

</div>
10 changes: 10 additions & 0 deletions install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash
insmod mailslot.ko

#reading major number of the mailslot driver
mailslot_major=$( cat /proc/devices | grep mailslot | cut -d " " -f 1 )

#inserting device file in /dev/
mknod -m 666 /dev/mailslot0 c $mailslot_major 0
mknod -m 666 /dev/mailslot1 c $mailslot_major 1
mknod -m 666 /dev/test_mailslot c $mailslot_major 2
213 changes: 213 additions & 0 deletions src/mailslot.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
/*
Copyright (C) 2017-2018 Riccardo Ostani.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#include "mailslot.h"

#include <linux/slab.h> /* for kzalloc */
#include <linux/mutex.h> /* for mutex */
#include <linux/uaccess.h> /* for copy_to_user and copy_from_user functions */
#include <linux/wait.h> /* for wait_queue */

typedef struct message {
char* content;
size_t size;
struct message* next;
} message_t;

struct mailslot {
struct mutex mutex;
wait_queue_head_t rd_queue, wr_queue;
message_t* head;
message_t* tail;
size_t max_msg_size;
int msg_count;
int id; /* needed only to help debugging! */
};

mailslot_t* mailslot_alloc( void ) {
return kzalloc( sizeof( mailslot_t ), GFP_KERNEL );
}

void mailslot_init( mailslot_t* slot, int id ) {
mutex_init( &( slot->mutex ) );
init_waitqueue_head( &( slot->rd_queue ) );
init_waitqueue_head( &( slot->wr_queue ) );
slot->head = NULL;
slot->tail = NULL;
slot->max_msg_size = DEFAULT_MAX_MSG_SIZE;
slot->id = id;
}

ssize_t mailslot_enqueue( mailslot_t* slot, const char* content, size_t size, int non_blocking ) {
int error;
int count = slot->msg_count;
message_t* msg = NULL;

if ( count == MAX_SLOT_SIZE ) {
printk( KERN_ERR "mailslot (id %d): cannot enqueue msg, slot is full\n", slot->id );
return -ENOSPC;
}

if ( size > slot->max_msg_size ) { /* all or nothing */
printk( KERN_ERR "mailslot (id %d): cannot write msg, size (%lu) greater than max allowed by the slot (%lu)\n", slot->id, size, slot->max_msg_size );
return -EPERM;
}

msg = kzalloc( sizeof( message_t ), non_blocking ? GFP_ATOMIC : GFP_KERNEL );
if ( msg == NULL ) {
printk( KERN_ERR "mailslot (id %d): failed to allocate space for the new msg\n", slot->id );
return non_blocking ? -EAGAIN : -ENOMEM;
}

msg->content = kzalloc( size, non_blocking ? GFP_ATOMIC : GFP_KERNEL );
if ( msg->content == NULL ) {
printk( KERN_ERR "mailslot (id %d): failed to allocate space for the new msg's content\n", slot->id );
kfree( msg );
return non_blocking ? -EAGAIN : -ENOMEM;
}

if ( non_blocking ) { /* disabling the pagefault handler, so that copy_from_user won't sleep */
pagefault_disable();
}
error = copy_from_user( msg->content, content, size );
if ( non_blocking ) {
pagefault_enable();
}
if ( error ) {
printk( KERN_ERR "mailslot (id %d): failed to copy msg from user space\n", slot->id );
kfree( msg->content );
kfree( msg );
return -EFAULT;
}
msg->size = size;
msg->next = NULL;

if ( count == 0 ) {
slot->head = msg;
} else {
slot->tail->next = msg;
}
slot->tail = msg;
slot->msg_count++;
mailslot_printqueue( slot ); /* debug help */

return size;
}

ssize_t mailslot_dequeue( mailslot_t* slot, char* buffer, size_t size, int non_blocking ) {
int res, error;
int count = slot->msg_count;
message_t* msg = NULL;

if ( count == 0 ) { /* not an error */
printk( KERN_INFO "mailslot (id %d): no msg to read, empty slot\n", slot->id );
return 0;
}

msg = slot->head;
if ( msg->size > size ) { /* all or nothing */
printk( KERN_ERR "mailslot (id %d): user buffer too small for the msg\n", slot->id );
return -EMSGSIZE;
}

if ( non_blocking ) {
pagefault_disable();
}
error = copy_to_user( buffer, msg->content, msg->size );
if ( non_blocking ) {
pagefault_enable();
}
if ( error ) {
printk( KERN_ERR "mailslot (id %d): failed to copy msg to user space\n", slot->id );
return -EFAULT;
}

res = msg->size;
slot->head = slot->head->next; /* if count == 1, here head becomes NULL! */
kfree( msg->content );
kfree( msg );
if ( count == 1 ) {
slot->tail = NULL; /* here head == NULL and tail == (deallocated) msg */
}
slot->msg_count--;
mailslot_printqueue( slot ); /* debug help */

return res;
}

int mailslot_lock( mailslot_t* slot, int non_blocking ) {
printk( KERN_INFO "mailslot (id %d): pid %d wants to lock the slot", slot->id, current->pid );
if ( non_blocking ) {
printk( KERN_CONT " without blocking\n" );
return mutex_trylock( &(slot->mutex) );
} else {
printk( KERN_CONT "\n" );
return mutex_lock_interruptible( &(slot->mutex) ) == 0;
}
}

void mailslot_unlock( mailslot_t* slot ) {
mutex_unlock( &(slot->mutex) );
}

int mailslot_wait_msg( mailslot_t* slot ) {
return wait_event_interruptible_exclusive( slot->rd_queue, slot->msg_count > 0 );
}

int mailslot_wait_space( mailslot_t* slot ) {
return wait_event_interruptible_exclusive( slot->wr_queue, slot->msg_count < MAX_SLOT_SIZE );
}

void mailslot_notify_msg( mailslot_t* slot ) {
wake_up_interruptible( &(slot->rd_queue) );
}

void mailslot_notify_space( mailslot_t* slot ) {
wake_up_interruptible( &(slot->wr_queue) );
}

void mailslot_set_max_msg_size( mailslot_t* slot, size_t size ) {
slot->max_msg_size = size;
}

void mailslot_free( mailslot_t* slot ) {
int i;
message_t* msg = NULL;
for ( i = 0; i < slot->msg_count; i++ ) {
msg = slot->head->next;
kfree( slot->head->content );
kfree( slot->head );
slot->head = msg;
}
kfree( slot );
}

void mailslot_printqueue( mailslot_t* slot ) {
message_t* msg = slot->head;
printk( KERN_INFO "mailslot (id %d): (slot content) head = ", slot->id );
while ( msg != NULL ) {
printk( KERN_CONT "\"%s\"", msg->content );
if ( msg->next != NULL ) {
printk( KERN_CONT ", " );
}
msg = msg->next;
}
if ( msg == NULL ){
printk( KERN_CONT " = tail\n" );
}
}
72 changes: 72 additions & 0 deletions src/mailslot.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
Copyright (C) 2017-2018 Riccardo Ostani.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#ifndef MAILSLOT_H
#define MAILSLOT_H

#include <linux/kernel.h>

#define DEFAULT_MAX_MSG_SIZE 256 /* default max size of a message data-unit */
#define LIMIT_MAX_MSG_SIZE 512 /* upper limit to the max size of a message data-unit */
#define MAX_SLOT_SIZE 64 /* max number of messages storable in a mailslot */

typedef struct mailslot mailslot_t;

/* Allocates a mailslot struct. */
mailslot_t* mailslot_alloc( void );

/* Initilizes the fields of a mailslot. */
void mailslot_init( mailslot_t* slot, int id );

/* Enqueues a message in a slot.
* Note: it must be called in a critical section (e.g. after a mailslot_lock) */
ssize_t mailslot_enqueue( mailslot_t* slot, const char* content, size_t size, int non_blocking );

/* Dequeues the oldest message in the slot.
* Note: it must be called in a critical section (e.g. after a mailslot_lock) */
ssize_t mailslot_dequeue( mailslot_t* slot, char* buffer, size_t size, int non_blocking );

/* Locks the access to the slot.
* It returns 1 if lock was acquired, 0 otherwise. */
int mailslot_lock( mailslot_t* slot, int non_blocking );

/* Unlocks the access to the slot. */
void mailslot_unlock( mailslot_t* slot );

/* Makes the caller sleep and wait for a message to be written in the slot. */
int mailslot_wait_msg( mailslot_t* slot );

/* Makes the caller sleep and wait for space availability in the slot. */
int mailslot_wait_space( mailslot_t* slot );

/* Wakes up all processes waiting for new messages in the slot. */
void mailslot_notify_msg( mailslot_t* slot );

/* Wakes up all processes waiting for space in the slot. */
void mailslot_notify_space( mailslot_t* slot );

/* Sets the max message size allowed in the slot. */
void mailslot_set_max_msg_size( mailslot_t* slot, size_t size );

/* Frees the mailslot memory. */
void mailslot_free( mailslot_t* slot );

/* Prints the content of the slot fifo queue. */
void mailslot_printqueue( mailslot_t* slot );

#endif
Loading

0 comments on commit 2bbeb7e

Please sign in to comment.