Can someone help me replace "lock_kernel" on a block device driver? - linux-kernel

Thank you for looking at this post. I am trying to patch up a network block device driver. If you need to see the sources they are at http : / / code.ximeta.com.
I noticed that lock_kernel() seems deprecated as of linux 2.6.37. I read "The new way of ioctl()" and found that device drivers now should perform a specific lock before operating.
So I would like some advice replacing this if possible.
I have found two sections in the current code that I think are related, in the block folder section.
Source
block->io.c
->ctrldev.c
I put snippets from each for your consideration.
io.c contains one call to lock_kernel:
NDAS_SAL_API xbool sal_file_get_size(sal_file file, xuint64* size)
{
definitions and declarations etc..
lock_kernel();
#ifdef HAVE_UNLOCKED_IOCTL
if (filp->f_op->unlocked_ioctl) {
some small statements
error = filp->f_op->unlocked_ioctl(filp, BLKGETSIZE64, (unsigned long)size);
actions if error or not etc.
}
#endif
unlock_kernel();
return ret;
}
And ctrldev.c contains the main io function:
#include <linux/spinlock.h> // spinklock_t
#include <linux/semaphore.h> // struct semaphore
#include <asm/atomic.h> // atomic
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/ide.h>
#include <linux/smp_lock.h>
#include <linux/time.h>
......
int ndas_ctrldev_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
lots of operations and functions.
return result;
}
Later ndas_ctrldev_ioctl function is set as the former .ioctl.
static struct file_operations ndasctrl_fops = {
.write = ndas_ctrldev_write,
.read = ndas_ctrldev_read,
.open = ndas_ctrldev_open,
.release = ndas_ctrldev_release,
.ioctl = ndas_ctrldev_ioctl,
};
Now I want to convert this to avoid using lock_kernel();
According to my understanding I will modified the former sections as below:
NDAS_SAL_API xbool sal_file_get_size(sal_file file, xuint64* size)
{
definitions and declarations etc..
#ifndef HAVE_UNLOCKED_IOCTL
lock_kernel();
#endif
#ifdef HAVE_UNLOCKED_IOCTL
if (filp->f_op->unlocked_ioctl) {
some small statements
error = filp->f_op->unlocked_ioctl(filp, BLKGETSIZE64, (unsigned long)size);
actions if error or not etc.
}
#endif
#ifndef HAVE_UNLOCKED_IOCTL
unlock_kernel();
#endif
return ret;
}
#ifdef HAVE_UNLOCKED_IOCTL
long ndas_ctrldev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
#else
int ndas_ctrldev_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
#endif
{
#ifdef HAVE_UNLOCKED_IOCTL
! add some sort of lock here !
#endif
lots of operations and functions.
#ifdef HAVE_UNLOCKED_IOCTL
! add unlock statement here !
#endif
return result;
}
static struct file_operations ndasctrl_fops = {
.write = ndas_ctrldev_write,
.read = ndas_ctrldev_read,
.open = ndas_ctrldev_open,
.release = ndas_ctrldev_release,
#ifdef HAVE_UNLOCKED_IOCTL
.unlocked_ioctl = ndas_ctrldev_ioctl,
#else
.ioctl = ndas_ctrldev_ioctl,
#endif
};
So, I would ask the following advice.
Does this look like the right
proceedure?
Do I understand correct to move the
lock into the io function?
Based on the includes in crtrldev.c, can you
recommend any lock off the top of
your head? (I tried to research some
other drivers dealing with filp and
lock_kernel, but I am too much a
noob to find the answer right away.)

The Big Kernel Lock (BKL) is more than deprecated - as of 2.6.39, it does not exist anymore.
The way the lock_kernel() conversion was done was to replace it by per-driver mutexes. If the driver is simple enough, you can simply create a mutex for the driver, and replace all uses of lock_kernel() and unlock_kernel() by the mutex lock/unlock calls. Note, however, that some functions used to be called with the BKL (the lock lock_kernel() used to lock) held; you will have to add lock/unlock calls to these functions too.
This will not work if the driver could acquire the BKL recursively; if that is the case, you would have to track it yourself to avoid deadlocks (this was done in the conversion of reiserfs, which depended somewhat heavily both in the recursive BKL behavior and in the fact that it was dropped when sleeping).
The next step after the conversion to a per-driver mutex would be to change it to use a per-device mutex instead of a per-driver mutex.

Here is the solution.
#if HAVE_UNLOCKED_IOCTL
#include <linux/mutex.h>
#else
#include <linux/smp_lock.h>
#endif
.
.
.
#if HAVE_UNLOCKED_IOCTL
mutex_lock(&fs_mutex);
#else
lock_kernel();
#endif
This only shows replacing the lock call. The other parts worked out as I guessed in the question part above concerning unlocked_ioctl. Thanks for checking and for helping.

Related

Accessing SuperBlock object of linux kernel in a system call

I am trying to access super block object which is defined in linux/fs.h.
But how to initialize the object so that we can access it's properties.
I found that alloc_super() is used to initialize super but how is it called?
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <linux/fs.h>
int main(){
printf("hello there");
struct super_block *sb;
return 0;
}
The answer is very much file system dependent, since different file systems will have different super block layouts and infact different arrangements of blocks.
For instance, ext2 file systems superblock is in a known location on disk (byte 1024), and has a known size (sizeof(struct superblock) bytes).
So a typical implementation (This is not a working code but with minor modification can be made to work ) of what you want would be:
struct superblock *read_superblock(int fd) {
struct superblock *sb = malloc(sizeof(struct superblock));
assert(sb != NULL);
lseek(fd, (off_t) 1024, SEEK_SET));
read(fd, (void *) sb, sizeof(struct superblock));
return sb;
}
Now, you can alloc superblock using linux/headers, or write your own struct that exactly matches with the ext2/ext3/etc/etc file systems superblock.
Then you must know where to find the superblock (the lseek() comes here).
Also you need to pass the disk file name file_descriptor to the function.
So do a
int fd = open(argv[1], O_RDONLY);
struct superblock * sb = read_superblock(fd);

Correct usage of sched_setaffinity with two parameters

I have recently found this prototype for the sched_setaffinity method:
extern long sched_setaffinity(pid_t pid, const struct cpumask *new_mask);
I am attempting to use this to set the affinity of a task but it doesn't seem to be working. This is my implementation:
#define _GNU_SOURCE
#include <linux/sched.h>
#include <linux/cpumask.h>
int set_aff (pid_t pid, int core)
{
static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS);
struct cpumask *const task_cpumask = to_cpumask(cpu_possible_bits);
cpumask_set_cpu(core, task_cpumask);
sched_setaffinity(pid, task_cpumask);
return 0;
}
My code compiles without any errors however when I try to call this method, it breaks. Does anyone know why?
Is there a better way to do this from inside a kernel method?
You should try this:
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(1, &cpuset);
if (sched_setaffinity(0, sizeof(cpu_set_t), &cpuset))
exit(1);

How to setup C/C++ project safely (file organisation)

I have a (large) C/C++ project that consists of both C and C++ languages. At some point it turned out that there are two C functions with identical names. Those functions are defined in two different *.c files in different locations. In general at the highest level, the project is C++. This problem was questioned and answered here
However still a question "how to organize those files safely" remains. How can I group such project so that there are no name conflicts, and I can be sure that proper function is called. Will writing a wrapper for each of those functions help?
That how it looks at the moment:
A.h //first declaration of function F
A.c //first definition of function F
B.h //second declaration of function F
B.c //second definition of function F
trying to make such thing:
extern "C"{
#include "A.h"
#include "B.h"
}
causes of course name conflict. What can I do to avoid this conflct, and have the robust code? Would such solution help:
A_Wrapper.h: //c++
extern "C"{
#include "A.h"
}
void WrapF_A(int x)
{
F(x);
}
B_Wrapper.h: //C++
extern "C"{
#include "B.h"
}
void WrapF_B(int x)
{
F(x);
}
and then in the program:
#include A_Wrapper.h
#include B_Wrapper.h
Modyfing each file in that project would be rather impossible as it cosists of hundreds of files, and i would probably damage some code rather. Is there a way to make an include file seen only in some part of the program?
EDIT:
So I created a simple project illustrating the problem, and tried to apply the hints given by doctorlove. However still multiple definition of F error occurs. What should I change? Project files:
A.h:
#ifndef A_H_INCLUDED
#define A_H_INCLUDED
int F(int x);
#endif // A_H_INCLUDED
A.c
#include "A.h"
int F(int x)
{
return x*x;
}
AWrapper.h:
#ifndef AWRAPPER_H_INCLUDED
#define AWRAPPER_H_INCLUDED
int AF(int x);
#endif // AWRAPPER_H_INCLUDED
AW.cpp:
#include "AWrapper.h"
extern "C"{
#include "A.h"
}
int AF(int x)
{
return F(x);
}
B.h:
#ifndef B_H_INCLUDED
#define B_H_INCLUDED
int F(int x);
#endif // B_H_INCLUDED
B.c:
#include "B.h"
int F(int x)
{
return -x*x;
}
BWrapper.h:
#ifndef BWRAPPER_H_INCLUDED
#define BWRAPPER_H_INCLUDED
int BF(int x);
#endif // BWRAPPER_H_INCLUDED
BW.cpp:
#include "BWrapper.h"
extern "C"{
#include "B.h"
}
int BF(int x)
{
return F(x);
}
Go with your wrapper idea, but write a facade (see also here) that exposes what you need from A, and what you need from B not all the functions in there.
You will end up with something like
//header Wrap_A.h
#ifndef WRAP_A_INCLUDED
#define WRAP_A_INCLUDED
//for some input Data left as an exercise for the reader...
double solve_with_A(Data data);
#endif
//header Wrap_B.h
#ifndef WRAP_B_INCLUDED
#define WRAP_B_INCLUDED
//for some input Data...
double solve_with_B(Data data);
#endif
Then make two cpp files that include all the conflicting headers files, those from A in A.cpp and those from B in B.cpp, so the conflicts don't happen. The solve_with_A and solve_with_B functions will then call all the things they need without without leaking them to the whole program and causing conflicts.
You might have to give some thought to what Data will actually be. You could define your own types, one for A and one for B. Just avoid exposing the implementation details in your wrapping/facade headers.
If headers are causing you pain, firewall them off in the naughty corner.
EDIT
Given you have two functions, F, if you put all the sources into one project the linker should and will complain it can see both. Instead, you need to make two static libraries, and just expose the wrapped version to your main project.

How can one share depth images between two processes?

I have 4 different depth cameras available to me: Kinect, Xtion, PMD nano, Softkinetic DepthSense.
I have the libraries that know how to read all of them: OpenNI, PMD drivers, Softkinetic drivers.
I would ideally like to make a simple grabber for each kind of camera and then just use it as a plugin into any other program i.e. get fast, non redundant access (i.e. not too many memory copies) to the data stream.
One of the problems is that in many cases I dont have the right library in 32 or 64 bit so I cant compile all grabbers in the same project.
What is the best way to achieve this?
I am a researcher so this idea isnt necessarily useful for production code but given this scenario my best solution has been to create a server process for each type of camera. Each server process knows how to load its own type of camera stream and then throws it into a shared memory space that other processes can read from.
It is obviously possible to use different kind of locking mechanisms but I have left the below code without any locks.
The server process will include the following:
#define BOOST_ALL_NO_LIB
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
using namespace std;
using namespace boost::interprocess;
struct sharedImage
{
enum { width = 320 };
enum { height = 240 };
enum { dataLength = width*height*sizeof(unsigned short) };
sharedImage(){}
interprocess_mutex mutex;
unsigned short data[dataLength];
};
shared_memory_object shm;
sharedImage * sIm;
mapped_region region;
int setupSharedMemory(){
// Clear the object if it exists
shared_memory_object::remove("ImageMem");
shm = shared_memory_object(create_only /*only create*/,"ImageMem" /*name*/,read_write/*read-write mode*/);
printf("Size:%i\n",sizeof(sharedImage));
//Set size
shm.truncate(sizeof(sharedImage));
//Map the whole shared memory in this process
region = mapped_region(shm, read_write);
//Get the address of the mapped region
void * addr = region.get_address();
//Construct the shared structure in the preallocated memory of shm
sIm = new (addr) sharedImage;
return 0;
}
int shutdownSharedMemory(){
shared_memory_object::remove("ImageMem");
return 0;
}
To start it up call setupSharedMemory() and to shut down call shutdownSharedMemory().
All the values are hard coded in this simple example but its easy to imagine making it more flexible.
Now lets assume that you are using SoftKinetic's DepthSense. So then you could write the following callback for the Depth node.
void onNewDepthSample(DepthNode node, DepthNode::NewSampleReceivedData data) {
//scoped_lock<interprocess_mutex> lock(sIm->mutex);
memcpy(sIm->data, data.depthMap, sIm->dataLength);
}
What this does is simply copies the latest depth map into the shared memory space.
You could also add a timestamp and a lock and anything else you need but this basic code works well enough for me so I will leave it as it is.
Now in some other process you can access the data in a very similar fashion.
The code below is what I use to get the live SoftKinetic DepthSense depth stream into Matlab for real time processing. This method has a huge advantage over trying to write my own mex wrapper specifically for SoftKinetic because I can use the same code for all the other cameras if I write servers for them.
#include <math.h>
#include <windows.h>
#include "mex.h"
#define BOOST_ALL_NO_LIB
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace boost::interprocess;
struct sharedImage
{
enum { width = 320 };
enum { height = 240 };
enum { dataLength = width*height*sizeof(short) };
sharedImage(): dirty(true){}
interprocess_mutex mutex;
uint8_t data[dataLength];
bool dirty;
};
void getFrame(unsigned short *D)
{
//Open the shared memory object.
shared_memory_object shm(open_only ,"ImageMem", read_write);
//Map the whole shared memory in this process
mapped_region region(shm ,read_write);
//Get the address of the mapped region
void * addr = region.get_address();
//Construct the shared structure in memory
sharedImage * sIm = static_cast<sharedImage*>(addr);
//scoped_lock<interprocess_mutex> lock(sIm->mutex);
memcpy((char*)D, (char*)sIm->data, sIm->dataLength);
}
void mexFunction(int nlhs, mxArray *plhs[ ], int nrhs, const mxArray *prhs[ ])
{
// Build outputs
mwSize dims[2] = {320, 240};
plhs[0] = mxCreateNumericArray(2, dims, mxUINT16_CLASS, mxREAL);
unsigned short *D = (unsigned short*)mxGetData(plhs[0]);
try
{
getFrame(D);
}
catch (interprocess_exception &ex)
{
mexPrintf("getFrame:%s\n", ex.what());
}
}
which on my computer I compile in Matlab with: mex getSKFrame.cpp -IC:\Development\boost_1_48_0
And then finally to use it in Matlab: D = getSKFrame()'; imagesc(D)

GetUserDefaultLocaleName() API is crashing

I have one application which reads user default locale in Windows Vista and above. When i tried calling the API for getting User default Locale API is crashing. Below is the code, It will be helpfull if any points the reason
#include <iostream>
#include <WinNls.h>
#include <Windows.h>
int main()
{
LPWSTR lpLocaleName=NULL;
cout << "Calling GetUserDefaultLocaleName";
int ret = GetUserDefaultLocaleName(lpLocaleName, LOCALE_NAME_MAX_LENGTH);
cout << lpLocaleName<<endl;
}
You need to have lpLocaleName initialized to a buffer prior to calling the API. As a general consensus, if an API has a LPWSTR data type parameter, call malloc or new on it first, to the desired length, in this case, LOCALE_NAME_MAX_LENGTH. Setting it to NULL and passing it to the API function is a guaranteed way to crash!
Hope this helps,
Best regards,
Tom.
In addition to the previous answers, you should also be aware that you can't print a wide string with cout; instead, you should use wcout.
So:
#include <iostream>
#include <WinNls.h>
#include <Windows.h>
#define ARRSIZE(arr) (sizeof(arr)/sizeof(*(arr)))
using namespace std;
int main()
{
WCHAR_T localeName[LOCALE_NAME_MAX_LENGTH]={0};
cout<<"Calling GetUserDefaultLocaleName";
int ret = GetUserDefaultLocaleName(localeName,ARRSIZE(localeName));
if(ret==0)
cout<<"Cannot retrieve the default locale name."<<endl;
else
wcout<<localeName<<endl;
return 0;
}
I believe you need to initialise lpLocaleName to an empty string of 256 chars (for example) then pass the length (256) where you have LOCALE_NAME_MAX_LENGTH

Resources