Skip to content

Commit 2bbeb7e

Browse files
committed
Add module code and update README
1 parent 1f23a0f commit 2bbeb7e

File tree

10 files changed

+961
-2
lines changed

10 files changed

+961
-2
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,5 @@ modules.order
5050
Module.symvers
5151
Mkfile.old
5252
dkms.conf
53+
54+
*.pdf

Makefile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CONFIG_MODULE_SIG=n
2+
WARN := -W -Wall -Wstrict-prototypes -Wmissing-prototypes
3+
ccflags-y := -O2
4+
5+
obj-m += mailslot.o
6+
mailslot-objs := ./src/mailslot_driver.o ./src/mailslot.o
7+
8+
all:
9+
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
10+
11+
clean:
12+
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

README.md

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,71 @@
1-
# LinuxMailslotsModule
2-
Windows mailslots for the Linux kernel
1+
<h1 align="center">
2+
Linux Mailslots Module
3+
</h1>
4+
5+
<h3 align="center">Windows mailslots for the Linux kernel</h3>
6+
7+
<p align="center">
8+
<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>
9+
<img src="https://img.shields.io/badge/OS-Linux-red.svg?style=flat-square&logo=linux&logoColor=white" alt="MSVC version">
10+
<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">
11+
<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>
12+
</p>
13+
<p align="center">
14+
<a href="#features">Features</a> •
15+
<a href="#building">Building</a> •
16+
<a href="#usage">Usage</a> •
17+
<a href="#license-gpl-v2">License</a>
18+
</p>
19+
20+
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.
21+
22+
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*.
23+
The original project specification can be found [here](https://www.dis.uniroma1.it/~quaglia/DIDATTICA/AOSV/examination.html).
24+
25+
## Features
26+
The module is a Linux driver for special device files supporting the following features:
27+
28+
+ **FIFO** (**F**irst **I**n **F**irst **O**ut) access policy semantic (via *open/close/read/write* services).
29+
+ **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).
30+
+ Support to **multiple instances** accessible concurrently by active processes/threads.
31+
+ **Blocking/Non-Blocking** runtime behaviour of I/O sessions (tunable via *open* or *ioctl* commands)
32+
+ Runtime configuration (via ioctl) of the following parameters:
33+
+ *Maximum message size* (configurable up to an absolute upper limit).
34+
+ *Maximum mailslot storage size* which is dynamically reserved to any individual mailslot.
35+
+ Compile-time configuration of the following parameters:
36+
+ *Range of device file minor numbers* supported by the driver (default: [0-255]).
37+
+ *Number of mailslot instances* (default: 256).
38+
39+
## Building
40+
41+
The project provides a Makefile and can be compiled using the `make` command line utility.
42+
43+
## Usage
44+
45+
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).
46+
Mailslot files can be created using the `mknod` command (for example usages, please see the `install.sh` script),
47+
48+
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).
49+
50+
## License (GPL v2)
51+
52+
This program is free software; you can redistribute it and/or modify
53+
it under the terms of the GNU General Public License as published by
54+
the Free Software Foundation; either version 2 of the License, or
55+
(at your option) any later version.
56+
57+
This program is distributed in the hope that it will be useful,
58+
but WITHOUT ANY WARRANTY; without even the implied warranty of
59+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
60+
GNU General Public License for more details.
61+
62+
You should have received a copy of the GNU General Public License along
63+
with this program; if not, write to the Free Software Foundation, Inc.,
64+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
65+
66+
<br/>
67+
<div align="center">
68+
69+
Copyright &copy; 2017 - 2018 Riccardo Ostani ([@rikyoz](https://github.com/rikyoz))
70+
71+
</div>

install.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/bin/bash
2+
insmod mailslot.ko
3+
4+
#reading major number of the mailslot driver
5+
mailslot_major=$( cat /proc/devices | grep mailslot | cut -d " " -f 1 )
6+
7+
#inserting device file in /dev/
8+
mknod -m 666 /dev/mailslot0 c $mailslot_major 0
9+
mknod -m 666 /dev/mailslot1 c $mailslot_major 1
10+
mknod -m 666 /dev/test_mailslot c $mailslot_major 2

src/mailslot.c

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
/*
2+
Copyright (C) 2017-2018 Riccardo Ostani.
3+
4+
This program is free software; you can redistribute it and/or
5+
modify it under the terms of the GNU General Public License
6+
as published by the Free Software Foundation; either version 2
7+
of the License, or (at your option) any later version.
8+
9+
This program is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with this program; if not, write to the Free Software
16+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17+
*/
18+
19+
#include "mailslot.h"
20+
21+
#include <linux/slab.h> /* for kzalloc */
22+
#include <linux/mutex.h> /* for mutex */
23+
#include <linux/uaccess.h> /* for copy_to_user and copy_from_user functions */
24+
#include <linux/wait.h> /* for wait_queue */
25+
26+
typedef struct message {
27+
char* content;
28+
size_t size;
29+
struct message* next;
30+
} message_t;
31+
32+
struct mailslot {
33+
struct mutex mutex;
34+
wait_queue_head_t rd_queue, wr_queue;
35+
message_t* head;
36+
message_t* tail;
37+
size_t max_msg_size;
38+
int msg_count;
39+
int id; /* needed only to help debugging! */
40+
};
41+
42+
mailslot_t* mailslot_alloc( void ) {
43+
return kzalloc( sizeof( mailslot_t ), GFP_KERNEL );
44+
}
45+
46+
void mailslot_init( mailslot_t* slot, int id ) {
47+
mutex_init( &( slot->mutex ) );
48+
init_waitqueue_head( &( slot->rd_queue ) );
49+
init_waitqueue_head( &( slot->wr_queue ) );
50+
slot->head = NULL;
51+
slot->tail = NULL;
52+
slot->max_msg_size = DEFAULT_MAX_MSG_SIZE;
53+
slot->id = id;
54+
}
55+
56+
ssize_t mailslot_enqueue( mailslot_t* slot, const char* content, size_t size, int non_blocking ) {
57+
int error;
58+
int count = slot->msg_count;
59+
message_t* msg = NULL;
60+
61+
if ( count == MAX_SLOT_SIZE ) {
62+
printk( KERN_ERR "mailslot (id %d): cannot enqueue msg, slot is full\n", slot->id );
63+
return -ENOSPC;
64+
}
65+
66+
if ( size > slot->max_msg_size ) { /* all or nothing */
67+
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 );
68+
return -EPERM;
69+
}
70+
71+
msg = kzalloc( sizeof( message_t ), non_blocking ? GFP_ATOMIC : GFP_KERNEL );
72+
if ( msg == NULL ) {
73+
printk( KERN_ERR "mailslot (id %d): failed to allocate space for the new msg\n", slot->id );
74+
return non_blocking ? -EAGAIN : -ENOMEM;
75+
}
76+
77+
msg->content = kzalloc( size, non_blocking ? GFP_ATOMIC : GFP_KERNEL );
78+
if ( msg->content == NULL ) {
79+
printk( KERN_ERR "mailslot (id %d): failed to allocate space for the new msg's content\n", slot->id );
80+
kfree( msg );
81+
return non_blocking ? -EAGAIN : -ENOMEM;
82+
}
83+
84+
if ( non_blocking ) { /* disabling the pagefault handler, so that copy_from_user won't sleep */
85+
pagefault_disable();
86+
}
87+
error = copy_from_user( msg->content, content, size );
88+
if ( non_blocking ) {
89+
pagefault_enable();
90+
}
91+
if ( error ) {
92+
printk( KERN_ERR "mailslot (id %d): failed to copy msg from user space\n", slot->id );
93+
kfree( msg->content );
94+
kfree( msg );
95+
return -EFAULT;
96+
}
97+
msg->size = size;
98+
msg->next = NULL;
99+
100+
if ( count == 0 ) {
101+
slot->head = msg;
102+
} else {
103+
slot->tail->next = msg;
104+
}
105+
slot->tail = msg;
106+
slot->msg_count++;
107+
mailslot_printqueue( slot ); /* debug help */
108+
109+
return size;
110+
}
111+
112+
ssize_t mailslot_dequeue( mailslot_t* slot, char* buffer, size_t size, int non_blocking ) {
113+
int res, error;
114+
int count = slot->msg_count;
115+
message_t* msg = NULL;
116+
117+
if ( count == 0 ) { /* not an error */
118+
printk( KERN_INFO "mailslot (id %d): no msg to read, empty slot\n", slot->id );
119+
return 0;
120+
}
121+
122+
msg = slot->head;
123+
if ( msg->size > size ) { /* all or nothing */
124+
printk( KERN_ERR "mailslot (id %d): user buffer too small for the msg\n", slot->id );
125+
return -EMSGSIZE;
126+
}
127+
128+
if ( non_blocking ) {
129+
pagefault_disable();
130+
}
131+
error = copy_to_user( buffer, msg->content, msg->size );
132+
if ( non_blocking ) {
133+
pagefault_enable();
134+
}
135+
if ( error ) {
136+
printk( KERN_ERR "mailslot (id %d): failed to copy msg to user space\n", slot->id );
137+
return -EFAULT;
138+
}
139+
140+
res = msg->size;
141+
slot->head = slot->head->next; /* if count == 1, here head becomes NULL! */
142+
kfree( msg->content );
143+
kfree( msg );
144+
if ( count == 1 ) {
145+
slot->tail = NULL; /* here head == NULL and tail == (deallocated) msg */
146+
}
147+
slot->msg_count--;
148+
mailslot_printqueue( slot ); /* debug help */
149+
150+
return res;
151+
}
152+
153+
int mailslot_lock( mailslot_t* slot, int non_blocking ) {
154+
printk( KERN_INFO "mailslot (id %d): pid %d wants to lock the slot", slot->id, current->pid );
155+
if ( non_blocking ) {
156+
printk( KERN_CONT " without blocking\n" );
157+
return mutex_trylock( &(slot->mutex) );
158+
} else {
159+
printk( KERN_CONT "\n" );
160+
return mutex_lock_interruptible( &(slot->mutex) ) == 0;
161+
}
162+
}
163+
164+
void mailslot_unlock( mailslot_t* slot ) {
165+
mutex_unlock( &(slot->mutex) );
166+
}
167+
168+
int mailslot_wait_msg( mailslot_t* slot ) {
169+
return wait_event_interruptible_exclusive( slot->rd_queue, slot->msg_count > 0 );
170+
}
171+
172+
int mailslot_wait_space( mailslot_t* slot ) {
173+
return wait_event_interruptible_exclusive( slot->wr_queue, slot->msg_count < MAX_SLOT_SIZE );
174+
}
175+
176+
void mailslot_notify_msg( mailslot_t* slot ) {
177+
wake_up_interruptible( &(slot->rd_queue) );
178+
}
179+
180+
void mailslot_notify_space( mailslot_t* slot ) {
181+
wake_up_interruptible( &(slot->wr_queue) );
182+
}
183+
184+
void mailslot_set_max_msg_size( mailslot_t* slot, size_t size ) {
185+
slot->max_msg_size = size;
186+
}
187+
188+
void mailslot_free( mailslot_t* slot ) {
189+
int i;
190+
message_t* msg = NULL;
191+
for ( i = 0; i < slot->msg_count; i++ ) {
192+
msg = slot->head->next;
193+
kfree( slot->head->content );
194+
kfree( slot->head );
195+
slot->head = msg;
196+
}
197+
kfree( slot );
198+
}
199+
200+
void mailslot_printqueue( mailslot_t* slot ) {
201+
message_t* msg = slot->head;
202+
printk( KERN_INFO "mailslot (id %d): (slot content) head = ", slot->id );
203+
while ( msg != NULL ) {
204+
printk( KERN_CONT "\"%s\"", msg->content );
205+
if ( msg->next != NULL ) {
206+
printk( KERN_CONT ", " );
207+
}
208+
msg = msg->next;
209+
}
210+
if ( msg == NULL ){
211+
printk( KERN_CONT " = tail\n" );
212+
}
213+
}

src/mailslot.h

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
Copyright (C) 2017-2018 Riccardo Ostani.
3+
4+
This program is free software; you can redistribute it and/or
5+
modify it under the terms of the GNU General Public License
6+
as published by the Free Software Foundation; either version 2
7+
of the License, or (at your option) any later version.
8+
9+
This program is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with this program; if not, write to the Free Software
16+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17+
*/
18+
19+
#ifndef MAILSLOT_H
20+
#define MAILSLOT_H
21+
22+
#include <linux/kernel.h>
23+
24+
#define DEFAULT_MAX_MSG_SIZE 256 /* default max size of a message data-unit */
25+
#define LIMIT_MAX_MSG_SIZE 512 /* upper limit to the max size of a message data-unit */
26+
#define MAX_SLOT_SIZE 64 /* max number of messages storable in a mailslot */
27+
28+
typedef struct mailslot mailslot_t;
29+
30+
/* Allocates a mailslot struct. */
31+
mailslot_t* mailslot_alloc( void );
32+
33+
/* Initilizes the fields of a mailslot. */
34+
void mailslot_init( mailslot_t* slot, int id );
35+
36+
/* Enqueues a message in a slot.
37+
* Note: it must be called in a critical section (e.g. after a mailslot_lock) */
38+
ssize_t mailslot_enqueue( mailslot_t* slot, const char* content, size_t size, int non_blocking );
39+
40+
/* Dequeues the oldest message in the slot.
41+
* Note: it must be called in a critical section (e.g. after a mailslot_lock) */
42+
ssize_t mailslot_dequeue( mailslot_t* slot, char* buffer, size_t size, int non_blocking );
43+
44+
/* Locks the access to the slot.
45+
* It returns 1 if lock was acquired, 0 otherwise. */
46+
int mailslot_lock( mailslot_t* slot, int non_blocking );
47+
48+
/* Unlocks the access to the slot. */
49+
void mailslot_unlock( mailslot_t* slot );
50+
51+
/* Makes the caller sleep and wait for a message to be written in the slot. */
52+
int mailslot_wait_msg( mailslot_t* slot );
53+
54+
/* Makes the caller sleep and wait for space availability in the slot. */
55+
int mailslot_wait_space( mailslot_t* slot );
56+
57+
/* Wakes up all processes waiting for new messages in the slot. */
58+
void mailslot_notify_msg( mailslot_t* slot );
59+
60+
/* Wakes up all processes waiting for space in the slot. */
61+
void mailslot_notify_space( mailslot_t* slot );
62+
63+
/* Sets the max message size allowed in the slot. */
64+
void mailslot_set_max_msg_size( mailslot_t* slot, size_t size );
65+
66+
/* Frees the mailslot memory. */
67+
void mailslot_free( mailslot_t* slot );
68+
69+
/* Prints the content of the slot fifo queue. */
70+
void mailslot_printqueue( mailslot_t* slot );
71+
72+
#endif

0 commit comments

Comments
 (0)