views:

219

answers:

3

In linux kernel programming, is there a way to check if a particular file descriptor is in use for a given process or if it's available?

A: 

If you're really programming in the Linux kernel then you'd look at the files_struct attached to the task_struct of the process you're interested in.

But what I think you mean is that you're writing a userspace program to run on Linux, using the kernel API. In which case it's a little harder.

There isn't a direct way to do it that I'm aware of. However you should be able to do a little hack with fcntl. Basically you query the status flags for the file descriptor, and if you get an error you know (more or less) that the file descriptor is invalid - and therefore usable.

However it's racy if you have multiple threads. Another thread could use the file descriptor after you've checked it. If you actually want to use that file descriptor maybe you want dup2() or F_DUPFD, but I'm not sure what you're actually trying to do.

Example code:

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

int main(void)
{
    int rc, fd;

    for (fd = 0; fd < 8; fd++) {
        errno = 0;
        rc = fcntl(fd, F_GETFL);

        if (rc >= 0)
            printf("fd %d is open\n", fd);
        else if (errno == EBADF)
            printf("fd %d is closed\n", fd);
        else
            printf("error %d querying fd %d \n", errno, fd);
    }

    return 0;
}
mpe
+1  A: 

Yes, you can test this:

struct files_struct * files = task->files;
struct fdtable *fdt;

spin_lock(&files->file_lock);

fdt = files_fdtable(files);
if (test_bit(fd, fdt->open_fds->fds_bits))
{
    /* fd is in use */
}

spin_unlock(&files->file_lock);

However, the information is potentially out of date as soon as you unlock the files struct, so the real question is what you're going to do with it?

caf
A: 

Assuming you are in the kernel and have a process context in struct task_struct* proc and you only want to check that the given fd corresponds to an open file in that process and not actually use the file somehow:

int is_valid_fd_for_process(int fd, struct task_struct* proc)
{
     int exists;

     rcu_read_lock();
     exists = (NULL != fcheck_files(proc->files, fd));
     rcu_read_unlock();

     return exists;
} 

In case you actually want to use the file struct that this fd addresses somehow or store it for later you should aquire a reference for it. See the code for fget which does that for the current process and adapt it for any process.

Inso Reiges