src/dbfs.c
changeset 27 461be4cd34a3
parent 26 61668c57f4bb
child 28 e944453ca924
equal deleted inserted replaced
26:61668c57f4bb 27:461be4cd34a3
    50 void dbfs_init (void *userdata, struct fuse_conn_info *conn) {
    50 void dbfs_init (void *userdata, struct fuse_conn_info *conn) {
    51     INFO("[dbfs.init] userdata=%p, conn=%p", userdata, conn);
    51     INFO("[dbfs.init] userdata=%p, conn=%p", userdata, conn);
    52 
    52 
    53 }
    53 }
    54 
    54 
    55 void dbfs_destroy (void *userdata) {
    55 void dbfs_destroy (void *arg) {
    56     INFO("[dbfs.destroy] userdata=%p", userdata);
    56     struct dbfs *ctx = arg;
    57 
    57     INFO("[dbfs.destroy %p]", ctx);
    58 
    58 
       
    59     // exit libevent
       
    60     event_base_loopexit(ctx->ev_base, NULL);
    59 }
    61 }
    60 
    62 
    61 /*
    63 /*
    62  * Check the result set.
    64  * Check the result set.
    63  *
    65  *
    64  * Returns;
    66  * Returns;
    65  *  -1  if the query failed, the columns do not match, or there are too many/few rows
    67  *  -1  if the query failed, the columns do not match, or there are too many/few rows (unless rows was zero)
    66  *  0   the results match
    68  *  0   the results match
    67  *  1   there were no results
    69  *  1   there were no results
    68  */
    70  */
    69 int _dbfs_check_res (const struct evsql_result_info *res, size_t rows, size_t cols) {
    71 int _dbfs_check_res (const struct evsql_result_info *res, size_t rows, size_t cols) {
    70     int err = 0;
    72     int err = 0;
    76     // not found?
    78     // not found?
    77     if (evsql_result_rows(res) == 0)
    79     if (evsql_result_rows(res) == 0)
    78         SERROR(err = 1);
    80         SERROR(err = 1);
    79 
    81 
    80     // duplicate rows?
    82     // duplicate rows?
    81     if (evsql_result_rows(res) != rows)
    83     if (rows && evsql_result_rows(res) != rows)
    82         ERROR("multiple rows returned");
    84         ERROR("wrong number of rows returned");
    83     
    85     
    84     // correct number of columns
    86     // correct number of columns
    85     if (evsql_result_cols(res) != 5)
    87     if (evsql_result_cols(res) != cols)
    86         ERROR("wrong number of columns: %zu", evsql_result_cols(res));
    88         ERROR("wrong number of columns: %zu", evsql_result_cols(res));
    87 
    89 
    88     // good
    90     // good
    89     return 0;
    91     return 0;
    90 
    92 
   140     if (0
   142     if (0
   141         ||  evsql_result_uint32(res, 0, 0, &ino,        0 ) // inodes.ino
   143         ||  evsql_result_uint32(res, 0, 0, &ino,        0 ) // inodes.ino
   142     )
   144     )
   143         EERROR(err = EIO, "invalid db data");
   145         EERROR(err = EIO, "invalid db data");
   144         
   146         
   145     INFO("[dbfs.lookup] -> ion=%u", ino);
   147     INFO("[dbfs.lookup] -> ino=%u", ino);
   146     
   148     
   147     // stat attrs
   149     // stat attrs
   148     if (_dbfs_stat_info(&e.attr, res, 0, 1))
   150     if (_dbfs_stat_info(&e.attr, res, 0, 1))
   149         goto error;
   151         goto error;
   150 
   152 
   247 
   249 
   248     const char *sql =
   250     const char *sql =
   249         "SELECT"
   251         "SELECT"
   250         " inodes.type, inodes.mode, inodes.size, count(*)"
   252         " inodes.type, inodes.mode, inodes.size, count(*)"
   251         " FROM inodes"
   253         " FROM inodes"
   252         " WHERE inodes.ino = ‰1::int4"
   254         " WHERE inodes.ino = $1::int4"
   253         " GROUP BY inodes.type, inodes.mode, inodes.size";
   255         " GROUP BY inodes.type, inodes.mode, inodes.size";
   254 
   256 
   255     static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) {
   257     static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) {
   256         EVSQL_PARAM ( UINT32 ),
   258         EVSQL_PARAM ( UINT32 ),
   257 
   259 
   277     if ((err = fuse_reply_err(req, err)))
   279     if ((err = fuse_reply_err(req, err)))
   278         EWARNING(err, "fuse_reply_err");
   280         EWARNING(err, "fuse_reply_err");
   279 }
   281 }
   280 
   282 
   281 struct dbfs_dirop {
   283 struct dbfs_dirop {
   282     struct fuse_file_info *fi;
   284     struct fuse_file_info fi;
   283     struct fuse_req *req;
   285     struct fuse_req *req;
   284 
   286 
   285     struct evsql_trans *trans;
   287     struct evsql_trans *trans;
       
   288     
       
   289     // dir/parent dir inodes
       
   290     uint32_t ino, parent;
   286     
   291     
   287     // opendir has returned and releasedir hasn't been called yet
   292     // opendir has returned and releasedir hasn't been called yet
   288     int open;
   293     int open;
       
   294 
       
   295     // for readdir
       
   296     struct dirbuf dirbuf;
   289 };
   297 };
   290 
   298 
   291 /*
   299 /*
   292  * Free the dirop, aborting any in-progress transaction.
   300  * Free the dirop, aborting any in-progress transaction.
   293  *
   301  *
   294  * req must be NULL.
   302  * req must be NULL.
   295  */
   303  */
   296 static void dbfs_dirop_free (struct dbfs_dirop *dirop) {
   304 static void dbfs_dirop_free (struct dbfs_dirop *dirop) {
   297     assert(dirop->req == NULL);
   305     assert(dirop);
   298 
   306     assert(!dirop->open);
   299     if (dirop->trans)
   307     assert(!dirop->req);
       
   308 
       
   309     if (dirop->trans) {
       
   310         WARNING("aborting transaction");
   300         evsql_trans_abort(dirop->trans);
   311         evsql_trans_abort(dirop->trans);
       
   312     }
       
   313 
       
   314     dirbuf_release(&dirop->dirbuf);
   301 
   315 
   302     free(dirop);
   316     free(dirop);
       
   317 }
       
   318 
       
   319 static void dbfs_opendir_info_res (const struct evsql_result_info *res, void *arg) {
       
   320     struct dbfs_dirop *dirop = arg;
       
   321     struct fuse_req *req = dirop->req; dirop->req = NULL;
       
   322     int err;
       
   323     
       
   324     assert(req != NULL);
       
   325    
       
   326     // check the results
       
   327     if ((err = _dbfs_check_res(res, 1, 2)))
       
   328         SERROR(err = (err ==  1 ? ENOENT : EIO));
       
   329 
       
   330     const char *type;
       
   331 
       
   332     // extract the data
       
   333     if (0
       
   334         ||  evsql_result_uint32(res, 0, 0, &dirop->parent,  1 ) // file_tree.parent
       
   335         ||  evsql_result_string(res, 0, 1, &type,           0 ) // inodes.type
       
   336     )
       
   337         SERROR(err = EIO);
       
   338 
       
   339     // is it a dir?
       
   340     if (_dbfs_mode(type) != S_IFDIR)
       
   341         EERROR(err = ENOTDIR, "wrong type: %s", type);
       
   342     
       
   343     INFO("[dbfs.opendir %p:%p] -> ino=%lu, parent=%lu, type=%s", dirop, req, (unsigned long int) dirop->ino, (unsigned long int) dirop->parent, type);
       
   344     
       
   345     // send the openddir reply
       
   346     if ((err = fuse_reply_open(req, &dirop->fi)))
       
   347         EERROR(err, "fuse_reply_open");
       
   348     
       
   349     // dirop is now open
       
   350     dirop->open = 1;
       
   351 
       
   352     // ok, wait for the opendir call
       
   353     return;
       
   354 
       
   355 error:
       
   356     if (err) {
       
   357         // abort the trans
       
   358         evsql_trans_abort(dirop->trans);
       
   359         
       
   360         dirop->trans = NULL;
       
   361 
       
   362         if ((err = fuse_reply_err(req, err)))
       
   363             EWARNING(err, "fuse_reply_err");
       
   364     }
       
   365     
       
   366     // free
       
   367     evsql_result_free(res);
   303 }
   368 }
   304 
   369 
   305 /*
   370 /*
   306  * The opendir transaction is ready
   371  * The opendir transaction is ready
   307  */
   372  */
   308 static void dbfs_dirop_ready (struct evsql_trans *trans, void *arg) {
   373 static void dbfs_dirop_ready (struct evsql_trans *trans, void *arg) {
   309     struct dbfs_dirop *dirop = arg;
   374     struct dbfs_dirop *dirop = arg;
   310     struct fuse_req *req = dirop->req; dirop->req = NULL;
   375     struct fuse_req *req = dirop->req;
   311     int err;
   376     struct dbfs *ctx = fuse_req_userdata(req);
   312 
   377     int err;
   313     INFO("[dbfs.openddir %p:%p] -> trans=%p", dirop, req, trans);
   378 
       
   379     assert(req != NULL);
       
   380 
       
   381     INFO("[dbfs.opendir %p:%p] -> trans=%p", dirop, req, trans);
   314 
   382 
   315     // remember the transaction
   383     // remember the transaction
   316     dirop->trans = trans;
   384     dirop->trans = trans;
   317 
   385     
   318     // send the openddir reply
   386     // first fetch info about the dir itself
   319     if ((err = fuse_reply_open(dirop->req, dirop->fi)))
   387     const char *sql =
   320         EERROR(err, "fuse_reply_open");
   388         "SELECT"
   321     
   389         " file_tree.parent, inodes.type"
   322     // dirop is now open
   390         " FROM file_tree LEFT OUTER JOIN inodes ON (file_tree.inode = inodes.ino)"
   323     dirop->open = 1;
   391         " WHERE file_tree.inode = $1::int4";
   324 
   392 
   325     // ok, wait for the next fs req
   393     static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) {
       
   394         EVSQL_PARAM ( UINT32 ),
       
   395 
       
   396         EVSQL_PARAMS_END
       
   397     };
       
   398 
       
   399     // build params
       
   400     if (0
       
   401         ||  evsql_param_uint32(&params, 0, dirop->ino)
       
   402     )
       
   403         SERROR(err = EIO);
       
   404         
       
   405     // query
       
   406     if (evsql_query_params(ctx->db, dirop->trans, sql, &params, dbfs_opendir_info_res, dirop) == NULL)
       
   407         SERROR(err = EIO);
       
   408 
       
   409     // ok, wait for the info results
   326     return;
   410     return;
   327 
   411 
   328 error:
   412 error:
       
   413     // we handle the req
       
   414     dirop->req = NULL;
       
   415     
       
   416     // free the dirop
   329     dbfs_dirop_free(dirop);
   417     dbfs_dirop_free(dirop);
   330 
   418     
   331     if ((err = fuse_reply_err(req, err)))
   419     if ((err = fuse_reply_err(req, err)))
   332         EWARNING(err, "fuse_reply_err");
   420         EWARNING(err, "fuse_reply_err");
   333 }
   421 }
   334 
   422 
   335 static void dbfs_dirop_done (struct evsql_trans *trans, void *arg) {
   423 static void dbfs_dirop_done (struct evsql_trans *trans, void *arg) {
   336     struct dbfs_dirop *dirop = arg;
   424     struct dbfs_dirop *dirop = arg;
   337     int err;
   425     struct fuse_req *req = dirop->req; dirop->req = NULL;
   338     
   426     int err;
   339 
   427     
       
   428     assert(req != NULL);
       
   429 
       
   430     INFO("[dbfs.releasedir %p:%p] -> OK", dirop, req);
       
   431 
       
   432     // forget trans
       
   433     dirop->trans = NULL;
       
   434     
       
   435     // just reply
       
   436     if ((err = fuse_reply_err(req, 0)))
       
   437         EWARNING(err, "fuse_reply_err");
       
   438     
       
   439     // we can free dirop
       
   440     dbfs_dirop_free(dirop);
   340 }
   441 }
   341 
   442 
   342 static void dbfs_dirop_error (struct evsql_trans *trans, void *arg) {
   443 static void dbfs_dirop_error (struct evsql_trans *trans, void *arg) {
   343     struct dbfs_dirop *dirop = arg;
   444     struct dbfs_dirop *dirop = arg;
   344     int err;
   445     int err;
   369     // allocate it
   470     // allocate it
   370     if ((dirop = calloc(1, sizeof(*dirop))) == NULL && (err = EIO))
   471     if ((dirop = calloc(1, sizeof(*dirop))) == NULL && (err = EIO))
   371         ERROR("calloc");
   472         ERROR("calloc");
   372 
   473 
   373     INFO("[dbfs.opendir %p:%p] ino=%lu, fi=%p", dirop, req, ino, fi);
   474     INFO("[dbfs.opendir %p:%p] ino=%lu, fi=%p", dirop, req, ino, fi);
   374         
   475     
   375     // store the dirop
   476     // store the dirop
   376     fi->fh = (uint64_t) dirop;
   477     // copy *fi since it's on the stack
       
   478     dirop->fi = *fi;
       
   479     dirop->fi.fh = (uint64_t) dirop;
   377     dirop->req = req;
   480     dirop->req = req;
   378     dirop->fi = fi;
   481     dirop->ino = ino;
   379 
   482 
   380     // start a new transaction
   483     // start a new transaction
   381     if (evsql_trans(ctx->db, EVSQL_TRANS_SERIALIZABLE, dbfs_dirop_error, dbfs_dirop_ready, dbfs_dirop_done, dirop))
   484     if ((dirop->trans = evsql_trans(ctx->db, EVSQL_TRANS_SERIALIZABLE, dbfs_dirop_error, dbfs_dirop_ready, dbfs_dirop_done, dirop)) == NULL)
   382         SERROR(err = EIO);
   485         SERROR(err = EIO);
   383     
   486     
   384     // XXX: handle interrupts
   487     // XXX: handle interrupts
   385     
   488     
   386     // wait
   489     // wait
   392 
   495 
   393     dbfs_dirop_free(dirop);
   496     dbfs_dirop_free(dirop);
   394 
   497 
   395     if ((err = fuse_reply_err(req, err)))
   498     if ((err = fuse_reply_err(req, err)))
   396         EWARNING(err, "fuse_reply_err");
   499         EWARNING(err, "fuse_reply_err");
       
   500 }
       
   501 
       
   502 static void dbfs_readdir_files_res (const struct evsql_result_info *res, void *arg) {
       
   503     struct dbfs_dirop *dirop = arg;
       
   504     struct fuse_req *req = dirop->req; dirop->req = NULL;
       
   505     int err;
       
   506     size_t row;
       
   507     
       
   508     assert(req != NULL);
       
   509     
       
   510     // check the results
       
   511     if ((err = _dbfs_check_res(res, 0, 4)) < 0)
       
   512         SERROR(err = EIO);
       
   513         
       
   514     INFO("[dbfs.readdir %p:%p] -> files: res_rows=%zu", dirop, req, evsql_result_rows(res));
       
   515         
       
   516     // iterate over the rows
       
   517     for (row = 0; row < evsql_result_rows(res); row++) {
       
   518         uint32_t off, ino;
       
   519         const char *name, *type;
       
   520 
       
   521         // extract the data
       
   522         if (0
       
   523             ||  evsql_result_uint32(res, row, 0, &off,          0 ) // file_tree.offset
       
   524             ||  evsql_result_string(res, row, 1, &name,         0 ) // file_tree.name
       
   525             ||  evsql_result_uint32(res, row, 2, &ino,          0 ) // inodes.ino
       
   526             ||  evsql_result_string(res, row, 3, &type,         0 ) // inodes.type
       
   527         )
       
   528             SERROR(err = EIO);
       
   529         
       
   530         INFO("\t%zu: off=%lu+2, name=%s, ino=%lu, type=%s", row, (long unsigned int) off, name, (long unsigned int) ino, type);
       
   531 
       
   532         // add to the dirbuf
       
   533         // offsets are just offset + 2
       
   534         if ((err = dirbuf_add(req, &dirop->dirbuf, off + 2, off + 3, name, ino, _dbfs_mode(type))) < 0 && (err = EIO))
       
   535             ERROR("failed to add dirent for inode=%lu", (long unsigned int) ino);
       
   536         
       
   537         // stop if it's full
       
   538         if (err > 0)
       
   539             break;
       
   540     }
       
   541 
       
   542     // send it
       
   543     if ((err = dirbuf_done(req, &dirop->dirbuf)))
       
   544         EERROR(err, "failed to send buf");
       
   545     
       
   546     // good, fallthrough
       
   547     err = 0;
       
   548 
       
   549 error:
       
   550     if (err) {
       
   551         // abort the trans
       
   552         evsql_trans_abort(dirop->trans);
       
   553         
       
   554         dirop->trans = NULL;
       
   555 
       
   556         // we handle the req
       
   557         dirop->req = NULL;
       
   558     
       
   559         if ((err = fuse_reply_err(req, err)))
       
   560             EWARNING(err, "fuse_reply_err");
       
   561     }
       
   562     
       
   563     // free
       
   564     evsql_result_free(res);
   397 }
   565 }
   398 
   566 
   399 static void dbfs_readdir (struct fuse_req *req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) {
   567 static void dbfs_readdir (struct fuse_req *req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) {
   400     struct dbfs *ctx = fuse_req_userdata(req);
   568     struct dbfs *ctx = fuse_req_userdata(req);
   401     struct dbfs_dirop *dirop = (struct dbfs_dirop *) fi->fh;
   569     struct dbfs_dirop *dirop = (struct dbfs_dirop *) fi->fh;
   402     int err;
   570     int err;
   403 
   571 
       
   572     assert(!dirop->req);
       
   573     assert(dirop->trans);
       
   574     assert(dirop->ino == ino);
       
   575     
   404     INFO("[dbfs.readdir %p:%p] ino=%lu, size=%zu, off=%zu, fi=%p : trans=%p", dirop, req, ino, size, off, fi, dirop->trans);
   576     INFO("[dbfs.readdir %p:%p] ino=%lu, size=%zu, off=%zu, fi=%p : trans=%p", dirop, req, ino, size, off, fi, dirop->trans);
   405 
   577 
   406     // update dirop
   578     // update dirop
   407     dirop->req = req;
   579     dirop->req = req;
   408     assert(dirop->fi == fi);
   580 
       
   581     // create the dirbuf
       
   582     if (dirbuf_init(&dirop->dirbuf, size, off))
       
   583         SERROR(err = EIO);
       
   584 
       
   585     // add . and ..
       
   586     // we set the next offset to 2, because all dirent offsets will be larger than that
       
   587     if ((err = (0
       
   588         ||  dirbuf_add(req, &dirop->dirbuf, 0, 1, ".",   dirop->ino,    S_IFDIR )
       
   589         ||  dirbuf_add(req, &dirop->dirbuf, 1, 2, "..",  
       
   590                         dirop->parent ? dirop->parent : dirop->ino,     S_IFDIR )
       
   591     )) && (err = EIO))
       
   592         ERROR("failed to add . and .. dirents");
   409 
   593 
   410     // select all relevant file entries
   594     // select all relevant file entries
   411     const char *sql = 
   595     const char *sql = 
   412         "SELECT"
   596         "SELECT"
   413         " \"file_tree.offset\", file_tree.name, inodes.ino, inodes.type"
   597         " file_tree.\"offset\", file_tree.name, inodes.ino, inodes.type"
   414         " FROM file_tree LEFT OUTER JOIN inodes ON (file_tree.inode = inodes.ino)"
   598         " FROM file_tree LEFT OUTER JOIN inodes ON (file_tree.inode = inodes.ino)"
   415         " WHERE file_tree.parent = $1::int4 AND \"file_tree.offset\" >= $2::int4"
   599         " WHERE file_tree.parent = $1::int4 AND file_tree.\"offset\" >= $2::int4"
   416         " LIMIT $3::int4";
   600         " LIMIT $3::int4";
   417 
   601 
   418     static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) {
   602     static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) {
   419         EVSQL_PARAM ( UINT32 ),
   603         EVSQL_PARAM ( UINT32 ),
   420         EVSQL_PARAM ( UINT32 ),
   604         EVSQL_PARAM ( UINT32 ),
   421         EVSQL_PARAM ( UINT32 ),
   605         EVSQL_PARAM ( UINT32 ),
   422 
   606 
   423         EVSQL_PARAMS_END
   607         EVSQL_PARAMS_END
   424     };
   608     };
   425 
   609 
   426     // XXX: incomplete
   610     // adjust offset to take . and .. into account
       
   611     if (off > 2)
       
   612         off -= 2;
       
   613     
       
   614     // build params
       
   615     if (0
       
   616         ||  evsql_param_uint32(&params, 0, dirop->ino)
       
   617         ||  evsql_param_uint32(&params, 1, off)
       
   618         ||  evsql_param_uint32(&params, 2, dirbuf_estimate(&dirop->dirbuf, 0))
       
   619     )
       
   620         SERROR(err = EIO);
       
   621 
       
   622     // query
       
   623     if (evsql_query_params(ctx->db, dirop->trans, sql, &params, dbfs_readdir_files_res, dirop) == NULL)
       
   624         SERROR(err = EIO);
       
   625 
       
   626     // good, wait
       
   627     return;
       
   628 
       
   629 error:
       
   630     // we handle the req
       
   631     dirop->req = NULL;
       
   632 
       
   633     // abort the trans
       
   634     evsql_trans_abort(dirop->trans); dirop->trans = NULL;
       
   635 
       
   636     if ((err = fuse_reply_err(req, err)))
       
   637         EWARNING(err, "fuse_reply_err");
       
   638 
   427 }
   639 }
   428 
   640 
   429 static void dbfs_releasedir (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi) {
   641 static void dbfs_releasedir (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi) {
   430     struct dbfs *ctx = fuse_req_userdata(req);
   642     struct dbfs *ctx = fuse_req_userdata(req);
   431     struct dbfs_dirop *dirop = (struct dbfs_dirop *) fi->fh;
   643     struct dbfs_dirop *dirop = (struct dbfs_dirop *) fi->fh;
   432     int err;
   644     int err;
   433 
   645 
   434     (void) ctx;
   646     (void) ctx;
       
   647     
       
   648     assert(!dirop->req);
       
   649     assert(dirop->ino == ino);
   435 
   650 
   436     INFO("[dbfs.releasedir %p:%p] ino=%lu, fi=%p : trans=%p", dirop, req, ino, fi, dirop->trans);
   651     INFO("[dbfs.releasedir %p:%p] ino=%lu, fi=%p : trans=%p", dirop, req, ino, fi, dirop->trans);
   437 
   652 
   438     // update dirop. Must keep it open so that dbfs_dirop_error won't free it
   653     // update dirop. Must keep it open so that dbfs_dirop_error won't free it
       
   654     // copy *fi since it's on the stack
       
   655     dirop->fi = *fi;
       
   656     dirop->fi.fh = (uint64_t) dirop;
   439     dirop->req = req;
   657     dirop->req = req;
   440     assert(dirop->fi == fi);
   658     
   441 
   659     if (dirop->trans) {
   442     // we can commit the transaction, although we didn't make any changes
   660         // we can commit the transaction, although we didn't make any changes
   443     // if this fails the transaction, then dbfs_dirop_error will take care of sending the error, and dirop->req will be
   661         // if this fails the transaction, then dbfs_dirop_error will take care of sending the error, and dirop->req will be
   444     // NULL
   662         // NULL
   445     if (evsql_trans_commit(dirop->trans))
   663         if (evsql_trans_commit(dirop->trans))
   446         SERROR(err = EIO);
   664             SERROR(err = EIO);
   447 
   665 
   448     // not open anymore
   666     } else {
       
   667         // trans failed earlier, so have releasedir just succeed
       
   668         if ((err = fuse_reply_err(req, 0)))
       
   669             EERROR(err, "fuse_reply_err");
       
   670 
       
   671         // req is done
       
   672         dirop->req = NULL;
       
   673     }
       
   674 
       
   675     // fall-through to cleanup
       
   676     err = 0;
       
   677 
       
   678 error:
       
   679     // the dirop is not open anymore and can be freed once done with
   449     dirop->open = 0;
   680     dirop->open = 0;
   450 
   681 
   451     // XXX: handle interrupts
   682     // if trans_commit triggered an error but didn't call dbfs_dirop_error, we need to take care of it
   452     
   683     if (err && dirop->req) {
   453     // wait
   684         int err2;
   454     return;
   685 
   455 
       
   456 error:
       
   457     if (dirop->req) {
       
   458         // we handle the req
   686         // we handle the req
   459         dirop->req = NULL;
   687         dirop->req = NULL;
   460 
   688 
       
   689         if ((err2 = fuse_reply_err(req, err)))
       
   690             EWARNING(err2, "fuse_reply_err");
       
   691     } 
       
   692     
       
   693     // same for trans, we need to abort it if trans_commit failed and fs_dirop_error didn't get called
       
   694     if (err && dirop->trans) {
   461         dbfs_dirop_free(dirop);
   695         dbfs_dirop_free(dirop);
   462 
   696     
   463         if ((err = fuse_reply_err(req, err)))
   697     } else
   464             EWARNING(err, "fuse_reply_err");
   698       // alternatively, if the trans error'd itself away (now or earlier), we don't need to keep the dirop around
       
   699       // anymore now that we've checkd its state
       
   700       if (!dirop->trans) {
       
   701         dbfs_dirop_free(dirop);
   465     }
   702     }
   466 }
   703 }
   467 
   704 
   468 struct fuse_lowlevel_ops dbfs_llops = {
   705 struct fuse_lowlevel_ops dbfs_llops = {
   469 
   706 
   473     .lookup         = dbfs_lookup,
   710     .lookup         = dbfs_lookup,
   474 
   711 
   475     .getattr        = dbfs_getattr,
   712     .getattr        = dbfs_getattr,
   476 
   713 
   477     .opendir        = dbfs_opendir,
   714     .opendir        = dbfs_opendir,
       
   715     .readdir        = dbfs_readdir,
   478     .releasedir     = dbfs_releasedir,
   716     .releasedir     = dbfs_releasedir,
   479 };
   717 };
   480 
   718 
   481 void dbfs_sql_error (struct evsql *evsql, void *arg) {
   719 void dbfs_sql_error (struct evsql *evsql, void *arg) {
   482     struct dbfs *ctx = arg;
   720     struct dbfs *ctx = arg;
   519     // clean shutdown
   757     // clean shutdown
   520 
   758 
   521 error :
   759 error :
   522     // cleanup
   760     // cleanup
   523     if (ctx.ev_fuse)
   761     if (ctx.ev_fuse)
   524         evfuse_close(ctx.ev_fuse);
   762         evfuse_free(ctx.ev_fuse);
   525 
   763 
   526     // XXX: ctx.db
   764     // XXX: ctx.db
   527     
   765     
   528     if (ctx.signals)
   766     if (ctx.signals)
   529         signals_free(ctx.signals);
   767         signals_free(ctx.signals);