18

I need to get the name of a file from a given file descriptor, inside a small linux kernel module that I wrote. I tried the solution given at Getting Filename from file descriptor in C, but for some reason, it prints out garbage values (on using readlink on /proc/self/fd/NNN as mentioned in the solution). How can I do it?

Community
  • 1
  • 1
Siddhant
  • 2,535
  • 4
  • 20
  • 22
  • possible duplicate of [sys_readlink fails EFAULT - alternative](http://stackoverflow.com/questions/8216871/sys-readlink-fails-efault-alternative) – ephemient Nov 23 '11 at 22:52

1 Answers1

27

Don't call SYS_readlink - use the same method that procfs does when one of those links is read. Start with the code in proc_pid_readlink() and proc_fd_link() in fs/proc/base.c.

Broadly, given an int fd and a struct files_struct *files from the task you're interested in (which you have taken a reference to), you want to do:

char *tmp;
char *pathname;
struct file *file;
struct path *path;

spin_lock(&files->file_lock);
file = fcheck_files(files, fd);
if (!file) {
    spin_unlock(&files->file_lock);
    return -ENOENT;
}

path = &file->f_path;
path_get(path);
spin_unlock(&files->file_lock);

tmp = (char *)__get_free_page(GFP_KERNEL);

if (!tmp) {
    path_put(path);
    return -ENOMEM;
}

pathname = d_path(path, tmp, PAGE_SIZE);
path_put(path);

if (IS_ERR(pathname)) {
    free_page((unsigned long)tmp);
    return PTR_ERR(pathname);
}

/* do something here with pathname */

free_page((unsigned long)tmp);

If your code is running in process-context (eg. invoked through a syscall) and the file descriptor is from the current process, then you can use current->files for the current task's struct files_struct *.

caf
  • 233,326
  • 40
  • 323
  • 462
  • Nice. That worked. Thanks! Quick question though. What purpose do the `path_get` and `path_put` calls serve (because removing them doesn't have much of an effect on my program)? Also, any idea why wouldn't `sys_readlink` work? – Siddhant Nov 25 '11 at 23:42
  • 1
    @Siddhant: The `path_get()` and `path_put()` calls are required for correctness, because they pin the path so that it doesn't go away while you are trying to work with it (all the `struct path` contains is a pair of pointers, to a `struct vfsmount` and a `struct dentry`). – caf Nov 26 '11 at 00:32
  • Also, why is it necessary to call `path_get` and get a reference to the path structure? – sherrellbc Jun 15 '15 at 15:07
  • Is there a reason or benefit of allocating a single page from memory as opposed to using `kmalloc`? Is it simply because you know a page would fit the worst-case requirement for the path data? It seems that the whole mess witih `IS_ERR` and `PTR_ERR` could be avoided by simply using the latter memory allocation method. – sherrellbc Jun 15 '15 at 15:25
  • @sherrellbc: Right, the pagesize is an upper limit on the possible size of the pathname, so there's no point in using `kmalloc()` - the return value of `d_path()` has to be tested with `IS_ERR()` regardless. It is necessary to call `path_get()` to prevent the path from going away after we release `->file_lock` (because at that point, the file could be closed by another thread in parallel). We don't want to keep `->file_lock` held for longer than necessary because it's a spinlock. – caf Jun 16 '15 at 01:49
  • In fact I'm not even sure if it's allowed to call `d_path()` while holding a spinlock. – caf Jun 16 '15 at 01:50
  • If your code is running in process-context ... then you can use **current->files** for the current task's **files_struct**. See this [answer](http://stackoverflow.com/a/17512619/2706918). – Nitinkumar Ambekar Aug 25 '15 at 06:01
  • Wouldn't be possible in this case to use, `rcu_read_lock()/rcu_read_unlock()`, instead of `spin_lock/spin_unlock`? it seems that is only reading the values of the files struct without updating them. – wallek876 Nov 05 '19 at 12:17
  • @wallek876: I believe that using RCU protection for this would require taking a reference on the `struct file` itself instead, because the file reference count can be decremented to zero while the RCU lock is held. – caf Nov 06 '19 at 03:13
  • Whats wrong with just `strcpy(n, file->f_path.dentry->d_name.name);` – teknopaul Jun 20 '21 at 17:38
  • @teknopaul: That will only look at the final component of the path, not the full pathname. It also races with dcache modifications like renames. – caf Jun 21 '21 at 14:54
  • I use d_path in __fput kprobe handler func to get file name from struct file , and it panic. Why is cannot used there ? – seamaner Dec 28 '22 at 06:01
  • @seamaner: I suggest you ask a new question and include more information about the panic and your code. – caf Dec 29 '22 at 07:36
  • @caf Thanks. I found that 'current->fs == NULL' and 'current->mm == NULL' too, so its a kthread. – seamaner Jan 04 '23 at 07:19