【问题标题】:Debugging a system call from FUSE从 FUSE 调试系统调用
【发布时间】:2010-12-04 20:02:40
【问题描述】:

我正在编写一个 FUSE 文件系统,它通过 sqlite 进行一些映射,然后将调用传递到底层文件系统(有点像 bbfs 的扩展)。当我尝试开始制作文件时,它开始给我带来麻烦。当我调用 mknod 时,它会返回 ERANGE。这是 strace 的尾部(文件系统安装在 test/ 上):

$ ./p4fs test/
$ strace touch test/kilo 2> logs
$ cat logs
...
fstat(3, {st_mode=S_IFREG|0644, st_size=56467024, ...}) = 0
mmap(NULL, 56467024, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fbf006bf000
close(3)                                = 0
close(0)                                = 0
open("test/kilo", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = -1 ERANGE (Numerical result out of range)
futimesat(AT_FDCWD, "test/kilo", NULL)  = 0
close(1)                                = 0
exit_group(0)                           = ?

这是我内部日志中的相关部分:

getattr: database opened
getattr: requesting attr for /kilo
db_getrowid: statement executed: finding rowid of /kilo
db_getrowid: mapped /kilo to rowid 0
getattr: does not exist: /kilo
mknod: database opened
mknod: statement executed: checking for existing path
mknod: calling db_mkdentry(db, /kilo, 100644, 0, 0)
db_mkdentry: parent is /
db_getrowid: statement executed: finding rowid of /
db_getrowid: mapped / to rowid 1
db_mkdentry: statement executed: creating dentry /kilo
db_getrowid: statement executed: finding rowid of /kilo
db_getrowid: mapped /kilo to rowid 3
p4fs: calling system mknod(3, 100644, 0)
p4fs: got errno 13

我正在寻找 (1) 解决这个直接问题的方法和 (2) 调试 FUSE 的好方法。我怀疑 ERANGE 来自 strtol(),但我不知道如何检查。我希望我可以让 gdb 在遇到回调时弹出...

谢谢!

编辑:哦,这是我的 mknod() 函数的源代码:

static int p4_mknod(const char *path, mode_t mode, dev_t dev) {
        sqlite3 *db;
        sqlite3_stmt *statement;
        char query[MAX_QUERY_LENGTH];
        int rc;
        int return_value;
        int path_exists = -1;

        OPEN_LOG("mknod")
        OPEN_DB(db_path, db)

        /* check for existing filename */
        sprintf(query,
                "SELECT COUNT(*) FROM dentry "
                "WHERE name = '%s'",
                path);
        sqlite3_prepare(db,
                query,
                -1,
                &statement,
                NULL);
        rc = sqlite3_step(statement);
        SQLITE3_ERRCHK("checking for existing path")
        path_exists = sqlite3_column_int(statement, 0);
        sqlite3_finalize(statement);

        if (path_exists <= 0) {
                int physical_rowid;
                char physical_name[MAX_QUERY_LENGTH];

                /* path is not already in db */
                syslog(LOG_DEBUG, "calling db_mkdentry(db, %s, %o, 0, 0)",
                        path, mode);
                db_mkdentry(db, (char *) path, mode, 0, 0);

                /* make the actual file */
                physical_rowid = db_getrowid(db, (char *) path);
                sprintf(physical_name, "%i", physical_rowid);
                syslog(LOG_DEBUG, "calling system mknod(%s, %o, %li)",
                        physical_name, mode, dev);
                return_value = mknod(physical_name, mode, dev);
        } else {
                syslog(LOG_INFO, "called on existing path");
                return_value = -EEXIST;
        }

        syslog(LOG_DEBUG, "errno %i", errno);

        return errno;
}

【问题讨论】:

    标签: c debugging fuse mknod


    【解决方案1】:

    几点建议:

    • 不要使用 sprintf 和朋友为 sqlite3 构建 SQL 语句。建议您在语句中使用托管参数,并使用 sqlite3_bind 函数将值绑定到它们。

    • 总是更喜欢 snprintf 而不是 sprintf 并检查其输出。它会让你免于很多麻烦。

    • 确保您在前台运行 FUSE 文件系统进程 - 它使调试更容易。

    你在 gdb 中尝试过断点吗?或者你代码中的一堆 perror() 调用来定位你提到的 errno 值来自哪里?

    顺便说一句,您提供的代码 sn-p 中没有 strtol() 调用,并且有一些宏没有定义。 IIRC 13 也是 EACCESS 的错误代码。

    编辑:

    FUSE API 中您可能错过的一些内容:

    一个主要的例外是 在 'errno' 中返回错误,即 操作应该返回否定的 错误值(-errno)直接。

    您似乎按原样返回 errno。

    【讨论】:

    • 感谢您的提示!我对 sqlite 很陌生,所以我很感激他们。我不知道有一种方法可以让我的回调在 gdb 中运行,但如果有一种方法我很想听听。我很担心 strtol,因为我查看了一些 mknod.c 实现的源代码并看到了它。
    • 只需将 gdb 附加到您的文件系统进程并在回调函数的开头设置一个断点。然后您通过其挂载点访问文件系统并触发您要研究其回调的操作。 GDB应该在回调时中断,您可以逐步分析回调的操作。
    • @thkala:优秀的补充建议,+1!
    【解决方案2】:

    这不是一个真正的答案,但我通过以 root 身份运行解决了这个问题。我怀疑它与 FUSE 有关,因为几个月前我在尝试让 sshfs 以普通用户身份运行时遇到了类似的问题。

    【讨论】:

      猜你喜欢
      • 2015-11-19
      • 2016-02-22
      • 2013-08-09
      • 2020-10-21
      • 2014-12-25
      • 1970-01-01
      • 2011-01-03
      • 1970-01-01
      • 2016-02-09
      相关资源
      最近更新 更多