2010-12-04 36 views
1

J'écris un système de fichiers FUSE qui effectue un mappage via sqlite, puis passe les appels au système de fichiers sous-jacent (en quelque sorte une extension sur bbfs). Cela a commencé à me causer des problèmes quand j'ai essayé de commencer à faire des fichiers. Quand j'appelle mknod, il revient avec ERANGE. Voici la queue d'un strace (système de fichiers est monté sur le test /):Débogage d'un appel système à partir de 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)       = ? 

et est ici la section correspondante de mon enregistrement interne:

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 

Je cherche (1) la solution ce problème immédiat et (2) un bon moyen de déboguer FUSE en général. J'ai une suspicion furtive que l'ERANGE vient de strtol(), mais je ne sais pas comment vérifier. Je voudrais pouvoir faire apparaître gdb quand il frappe le rappel ...

Merci!

EDIT: Oh, voici la source de ma fonction 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; 
} 

Répondre

0

Ce n'est pas vraiment une réponse, mais j'ai contourné le problème en courant en tant que root. Je suppose que cela a quelque chose à voir avec FUSE, parce que j'ai eu un problème similaire en essayant de faire fonctionner sshfs en tant qu'utilisateur normal il y a quelques mois.

2

A quelques conseils:

  • Ne pas utiliser sprintf et des amis pour créer des instructions SQL pour sqlite3 . Il est recommandé d'utiliser les paramètres hébergés dans votre instruction et de leur lier des valeurs à l'aide des fonctions sqlite3_bind.

  • Toujours préférer snprintf au lieu de sprintf et vérifier sa sortie. Cela vous évitera beaucoup de problèmes. Assurez-vous que vous exécutez votre processus de système de fichiers FUSE au premier plan - cela facilite le débogage.

Avez-vous essayé des points d'arrêt dans gdb? Ou un tas d'appels perror() dans votre code pour localiser l'origine de la valeur errno que vous avez mentionnée? Par ailleurs, il n'y a pas d'appel strtol() dans l'extrait de code que vous avez fourni et il y a quelques macros sans leurs définitions. Aussi IIRC 13 est le code d'erreur pour EACCESS.

EDIT:

Quelque chose que vous avez peut-être manqué de la FUSE API:

Une exception majeure est qu'au lieu de retourner une erreur dans « errno », l'opération doit retourner le réduit à néant valeur d'erreur (-errno) directement.

Vous semblez retourner errno tel quel.

+0

Merci pour les conseils! Je suis assez nouveau à sqlite, donc je les apprécie. Je ne suis pas au courant d'un moyen d'exécuter mes rappels dans gdb, mais s'il y a un moyen que j'aimerais en entendre parler. J'étais inquiet au sujet de strtol parce que j'avais regardé la source pour quelques implémentations de mknod.c et l'ai vu. – Jay

+0

Connectez simplement gdb à votre processus de système de fichiers et définissez un point d'arrêt au début de la fonction de rappel. Ensuite, vous accédez au système de fichiers via son point de montage et déclenchez l'opération dont vous souhaitez étudier le rappel. GDB doit interrompre le callback et vous pouvez analyser l'opération de votre callback étape par étape. – thkala

+0

@thkala: Excellents conseils supplémentaires, +1! –