0

Linux 3.2.2 内核

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

4

1 回答 1

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

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

快乐的黑客,祝你好运。

于 2012-12-09T03:56:08.927 回答