2010-12-04 128 views
1

我正在寫一個FUSE文件系統,它通過sqlite執行一些映射,然後將調用傳遞到底層文件系統(某種程度上是bbfs上的擴展)。當我嘗試開始製作文件時,它開始給我帶來麻煩。當我打電話給mknod時,它會返回ERANGE。下面是一個strace的尾部(文件系統被安裝在測試/):從FUSE調試系統調用

$ ./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; 
} 

回答

0

這不是一個真正的答案,但我通過以root身份運行來解決問題。我懷疑它與FUSE有關,因爲我在幾個月前試圖讓sshfs像普通用戶那樣運行時遇到了類似的問題。

2

建議幾塊:

  • 不要使用sprintf和朋友建立sqlite3的SQL語句。建議您在語句中使用託管參數,並使用sqlite3_bind函數將值綁定到它們。

  • 始終優先使用snprintf而不是sprintf並檢查其輸出。它可以爲你節省很多麻煩。

  • 請確保您在前臺運行FUSE文件系統進程 - 它使調試更容易。

你在gdb中試過斷點嗎?或者在你的代碼中調用一堆perror()來定位你提到的errno值來自哪裏?

順便說一句,在你提供的代碼片段中沒有strtol()調用,並且有幾個宏沒有它們的定義。另外IIRC 13是EACCESS的錯誤代碼。

編輯:

一些你可能已經從FUSE API錯過:

的一個主要例外是不是 在「錯誤號」返回一個錯誤, 操作應返回否定 錯誤值(-errno)直接。

您似乎正在返回errno。

+0

感謝您的提示!我對sqlite很新,所以我很感激他們。我沒有意識到讓我的回調函數在gdb中運行的方法,但是如果有我喜歡聽到的方法。我很擔心strtol,因爲我曾經看過mknod.c的幾個實現的源代碼並看到它。 – Jay 2010-12-04 22:31:33