|
Session Module
|
Author: Federico Alfano
It's a subsystem that makes the user able to access a file using sessions. In this way every modification is not visible until the session is close. Many processes can access concurrently a given file. The system provides also some statistical information into the /sys/kernel/session-module directory where the user can:
The idea is to create a new file, copy the old one into it and then redirect all the VFS operations on the session file overwriting the file operations. At the close, the session file is will be copied back into the original one and then is unlinked.
The module needs to be compiled and then inserted, so with a terminal open into the module directory we need to launch the following commands:
On the contrary if we want to remove the module this is the right command:
The user can be allowed to use the module's facilities by installing the userspace library into the libsession folder with those commands
and then copying this code inside the source of your program
finally you need to compile with the -lsession flag
The userspace library is a simple interface that provides the user a set of operations to interact with the module. In particular the operations needed are:
All the operations are a call to the facilities provided by the module
The subsystem has two global rbtrees that are represented respectively by:
They contain the counter for the per-process sessions and the per-file sessions. The system relies also on two global variables:
The former is used to store the current base path where the sessions can live, the latter keeps track of the total number of sessions. All data can be read into the /sys directory and the path can also be modified from the user.
The initialization allocates dynamically a MAJOR and a single MINOR for the char device and then initializes that and set the global variable my_cdev that is a struct defined into the header, containing the char device and a kobject. The next step is the build of the sysfs tree that contains all the files needed for keeping track of sessions and for managing the path
The last step is to set the PWD as default base path
The device initialization wants file_operations structure in order to control the behaviour of the module; the following implementations only need three of them:
The third one is the essence of the module, so it deserves a dedicated paragraph.
It's called when the user wants to start to work with sessions, so the first thing to do is to check if a session is already open and return an EEXIST error if it's so
after that, it will create a node into the rbtree containing the processes:
The insertion is sensitive to race conditions, so it keeps a rwlock that is managed into the helper function in tree_utils.c. And finally it creates a file into /sys/kernel/session_module/proc directory with the number of open sessions.
Basically, the release method is a check to verify if the user has closed the module in the right way.
The function is in charge to manage all the operations on the file, let's see them in detail:
This is the operation called at the opening of the session. After some checks on the validity of the file and of permissions it performs the following operations:
this file will be pointed out by the private_data field which is located into the original file. This one is a special structure defined in the header which contains the session file pointer, the absolute path and a semaphore that is used to protect sessions during the close.
And finally it increments the global counter and the counter of the sessions opened by the process
The close_session is responsible of closing the file and of copying the content of the session into the original file. All is done thanks to the function flush that after some operations makes its job:
after that it restores the default file operations
The flush returns an EPIPE error if the given file is removed from the filesystem, checking at the variable i_nlink
The whole developement had a test driven approach, all tests are contained into the tests/unit_tests folder, they were performed throught the check, a unit test framework. In particular the file test.c contains the main functions tested during the development, looking the code it's easy to understand that the tests were about:
The file perf_test compiled into the make with the -pg option tries many times a write operation with and without sessions:
The tests are performed initially with empty file and they shows no significant drop of performances with a relative low number of try. When tries are increased with the O_APPEND mode (more than 10k) the write with session takes more than the 99% of the time. The analysis is made with gproof with the following command into the terminal after the execution:
so the file little_file_analysis contains the report of the previous test.
the second test is performed with a medium file (2MB instead of 100byte) and 1k tries and with 10k tries. We can see that the drop of performace always belongs to the vfs_copy_file_range call into the kernel as we expected. All analysis are provided into the test folder.
All the tests were performed on a LUbuntu 16 distro with kernel version: 4.15.0.
1.8.11