linux内核正确取消链接文件的方法

时间:2012-12-07 06:49:04

标签: c linux kernel

Linux 3.2.2内核

我检查了fs / namei.c中的源代码,发现do_unlinkat执行整个操作但是使用了用户空间指针。我想知道是否有一个函数执行此操作,除了在内核空间(我确实有文件的结构路径,inode和dentry) 我可以将函数中的代码复制到我自己的代码中。但我只是想知道它是如何运作的?

1 个答案:

答案 0 :(得分:0)

您完全了解fs/namei.c:do_unlinkat()功能吗?除了使用

之外,它完全符合您的要求
     error = user_path_parent(dfd, pathname, &nd, &name);
     if (error)
         return error;

查找struct nameidata。如果成功,pathname的内核端副本将存储在name中(必须使用putname(name)释放。)

但是,同一个文件也包含user_path_parent()函数的实现。这很简单,所以你应该毫不费力地理解它的作用。实际上,除了将用户空间 - pathname复制到内核端name之外,它实际上只是进行do_path_lookup()调用,它仅在内核端结构上运行。

使用上述内容,您可以对do_unlinkat()进行少量修改,以实现您自己的内核端unlinkat()功能。如果这是代码,你希望有一天会被上游接受,你也应该重构这两个函数,这样就没有重复的代码了。

可能是一些东西
/*
 * Make sure that the actual truncation of the file will occur outside its
 * directory's i_mutex.  Truncate can take a long time if there is a lot of
 * writeout happening, and we don't want to prevent access to the directory
 * while waiting on the I/O.
 */
static long kern_unlinkat(int dfd, const char *name)
{
    long error;
    struct dentry *dentry;
    struct nameidata nd;
    struct inode *inode = NULL;

    error = do_path_lookup(dfd, name, LOOKUP_PARENT, &nd);
    if (error)
        return error;

    error = -EISDIR;
    if (nd.last_type != LAST_NORM)
        goto exit1;

    nd.flags &= ~LOOKUP_PARENT;
    error = mnt_want_write(nd.path.mnt);
    if (error)
        goto exit1;

    mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
    dentry = lookup_hash(&nd);
    error = PTR_ERR(dentry);
    if (!IS_ERR(dentry)) {
        /* Why not before? Because we want correct error value */
        if (nd.last.name[nd.last.len])
            goto slashes;
        inode = dentry->d_inode;
        if (!inode)
            goto slashes;
        ihold(inode);
        error = security_path_unlink(&nd.path, dentry);
        if (error)
            goto exit2;
        error = vfs_unlink(nd.path.dentry->d_inode, dentry);
exit2:
        dput(dentry);
    }
    mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
    if (inode)
        iput(inode);    /* truncate the inode here */
    mnt_drop_write(nd.path.mnt);
exit1:
    path_put(&nd.path);
    return error;

slashes:
    error = !dentry->d_inode ? -ENOENT :
        S_ISDIR(dentry->d_inode->i_mode) ? -EISDIR : -ENOTDIR;
    goto exit2;
}

static long do_unlinkat(int dfd, const char __user *pathname)
{
    long error;
    char *name = getname(pathname);

    if (IS_ERR(name))
        return PTR_ERR(name);

    error = kern_unlinkat(dfd, name);

    putname(name);

    return error;
}

EXPORT_SYMBOL(kern_unlink);

如果以上工作 - 我没有费心去测试它;所有由您决定的 - 然后您可以在自己的内核模块中使用kern_unlinkat(directoryfd, pathname)kern_unlinkat(AT_FDCWD, pathname)通过在内核端字符串pathname中指定其路径名来删除文件。 / p>

如果您已经拥有了nameidata,那么您显然可以更改上述内容以匹配常见代码和不代码代码。但是,考虑到细节的棘手(特别是dentry锁定),如果我是你,我只会使用路径名。

快乐的黑客,祝你好运。