# HG changeset patch # User Tero Marttila # Date 1224186989 -10800 # Node ID d8fabd347a8e347a9a07394be6db44c7b5d45b75 # Parent 5de62ca9a5aa162537722e9c27674992c7a94c97 working open+read+flush+release diff -r 5de62ca9a5aa -r d8fabd347a8e Makefile --- a/Makefile Thu Oct 16 22:04:53 2008 +0300 +++ b/Makefile Thu Oct 16 22:56:29 2008 +0300 @@ -19,8 +19,8 @@ BIN_PATHS = $(addprefix bin/,$(BIN_NAMES)) # complex modules -EVSQL_OBJS = obj/evsql.o obj/evsql_util.o obj/evpq.o -DBFS_OBJS = obj/dbfs/dbfs.o obj/dbfs/common.o obj/dbfs/core.o obj/dbfs/op_base.o obj/dbfs/dirop.o obj/dirbuf.o +EVSQL_OBJS = obj/evsql/evsql.o obj/evsql/util.o obj/evpq.o +DBFS_OBJS = obj/dbfs/dbfs.o obj/dbfs/common.o obj/dbfs/core.o obj/dbfs/op_base.o obj/dbfs/dirop.o obj/dirbuf.o obj/dbfs/fileop.o # first target all: ${BIN_PATHS} diff -r 5de62ca9a5aa -r d8fabd347a8e src/dbfs.c --- a/src/dbfs.c Thu Oct 16 22:04:53 2008 +0300 +++ b/src/dbfs.c Thu Oct 16 22:56:29 2008 +0300 @@ -38,8 +38,8 @@ ERROR("signals_default"); // setup dbfs - if ((ctx = dbfs_open(ev_base, &fuse_args, db_conninfo)) == NULL) - ERROR("dbfs_open"); + if ((ctx = dbfs_new(ev_base, &fuse_args, db_conninfo)) == NULL) + ERROR("dbfs_new"); // run libevent INFO("running libevent loop"); @@ -51,7 +51,7 @@ error : if (ctx) - dbfs_release(ctx); + dbfs_free(ctx); if (signals) signals_free(signals); diff -r 5de62ca9a5aa -r d8fabd347a8e src/dbfs.h --- a/src/dbfs.h Thu Oct 16 22:04:53 2008 +0300 +++ b/src/dbfs.h Thu Oct 16 22:56:29 2008 +0300 @@ -15,11 +15,11 @@ /* * Create the evsql and evfuse contexts and run the fs */ -struct dbfs *dbfs_open (struct event_base *ev_base, struct fuse_args *args, const char *db_conninfo); +struct dbfs *dbfs_new (struct event_base *ev_base, struct fuse_args *args, const char *db_conninfo); /* * Release the dbfs's resources and free it */ -void dbfs_release (struct dbfs *ctx); +void dbfs_free (struct dbfs *ctx); #endif /* DBFS_H */ diff -r 5de62ca9a5aa -r d8fabd347a8e src/dbfs/common.c --- a/src/dbfs/common.c Thu Oct 16 22:04:53 2008 +0300 +++ b/src/dbfs/common.c Thu Oct 16 22:56:29 2008 +0300 @@ -50,14 +50,15 @@ int err = 0; uint16_t mode; - uint64_t size, nlink; + uint32_t size = 0; // NULL for non-REG inodes + uint64_t nlink; const char *type; // extract the data if (0 || evsql_result_string(res, row, col_offset + 0, &type, 0 ) // inodes.type || evsql_result_uint16(res, row, col_offset + 1, &mode, 0 ) // inodes.mode - || evsql_result_uint64(res, row, col_offset + 2, &size, 0 ) // inodes.size + || evsql_result_uint32(res, row, col_offset + 2, &size, 1 ) // size || evsql_result_uint64(res, row, col_offset + 3, &nlink, 0 ) // count(*) ) EERROR(err = EIO, "invalid db data"); diff -r 5de62ca9a5aa -r d8fabd347a8e src/dbfs/core.c --- a/src/dbfs/core.c Thu Oct 16 22:04:53 2008 +0300 +++ b/src/dbfs/core.c Thu Oct 16 22:56:29 2008 +0300 @@ -57,10 +57,10 @@ // query and params const char *sql = "SELECT" - " inodes.ino, inodes.type, inodes.mode, inodes.size, count(*)" + " inodes.ino, inodes.type, inodes.mode, dbfs_lo_size(data), count(*)" " FROM file_tree INNER JOIN inodes ON (file_tree.inode = inodes.ino)" " WHERE file_tree.parent = $1::int4 AND file_tree.name = $2::varchar" - " GROUP BY inodes.ino, inodes.type, inodes.mode, inodes.size"; + " GROUP BY inodes.ino, inodes.type, inodes.mode, data"; static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) { EVSQL_PARAM ( UINT32 ), @@ -130,10 +130,10 @@ const char *sql = "SELECT" - " inodes.type, inodes.mode, inodes.size, count(*)" + " inodes.type, inodes.mode, dbfs_lo_size(data), count(*)" " FROM inodes" " WHERE inodes.ino = $1::int4" - " GROUP BY inodes.type, inodes.mode, inodes.size"; + " GROUP BY inodes.type, inodes.mode, data"; static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) { EVSQL_PARAM ( UINT32 ), diff -r 5de62ca9a5aa -r d8fabd347a8e src/dbfs/dbfs.c --- a/src/dbfs/dbfs.c Thu Oct 16 22:04:53 2008 +0300 +++ b/src/dbfs/dbfs.c Thu Oct 16 22:56:29 2008 +0300 @@ -4,7 +4,6 @@ #include "dbfs.h" #include "../dbfs.h" #include "../lib/log.h" -#include "../lib/misc.h" static struct fuse_lowlevel_ops dbfs_llops = { @@ -15,6 +14,12 @@ .getattr = dbfs_getattr, + .open = dbfs_open, + .read = dbfs_read, + // .write = dbfs_write, + .flush = dbfs_flush, + .release = dbfs_release, + .opendir = dbfs_opendir, .readdir = dbfs_readdir, .releasedir = dbfs_releasedir, @@ -43,7 +48,7 @@ event_base_loopbreak(ctx->ev_base); } -struct dbfs *dbfs_open (struct event_base *ev_base, struct fuse_args *args, const char *db_conninfo) { +struct dbfs *dbfs_new (struct event_base *ev_base, struct fuse_args *args, const char *db_conninfo) { struct dbfs *ctx = NULL; // alloc ctx @@ -66,12 +71,12 @@ error: if (ctx) - dbfs_release(ctx); + dbfs_free(ctx); return NULL; } -void dbfs_release (struct dbfs *ctx) { +void dbfs_free (struct dbfs *ctx) { // cleanup if (ctx->ev_fuse) { evfuse_free(ctx->ev_fuse); diff -r 5de62ca9a5aa -r d8fabd347a8e src/dbfs/dirop.c --- a/src/dbfs/dirop.c Thu Oct 16 22:04:53 2008 +0300 +++ b/src/dbfs/dirop.c Thu Oct 16 22:56:29 2008 +0300 @@ -228,12 +228,12 @@ */ void dbfs_readdir (struct fuse_req *req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { struct dbfs *ctx = fuse_req_userdata(req); - struct dbfs_dirop *dirop = (struct dbfs_dirop *) fi->fh; + struct dbfs_dirop *dirop; int err; // get the op if ((dirop = (struct dbfs_dirop *) dbfs_op_req(req, ino, fi)) == NULL) - SERROR(err = EIO); + return; INFO("[dbfs.readdir %p:%p] ino=%lu, size=%zu, off=%zu, fi=%p : trans=%p", dirop, req, ino, size, off, fi, dirop->base.trans); diff -r 5de62ca9a5aa -r d8fabd347a8e src/dbfs/fileop.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dbfs/fileop.c Thu Oct 16 22:56:29 2008 +0300 @@ -0,0 +1,245 @@ +#include +#include + +#include + +#include "dbfs.h" +#include "op_base.h" +#include "../lib/log.h" + +struct dbfs_fileop { + struct dbfs_op base; + + uint32_t lo_fd; +}; + +static void _dbfs_fileop_free (struct dbfs_op *op_base) { + struct dbfs_fileop *fop = (struct dbfs_fileop *) op_base; + + /* no-op */ + (void) fop; +} + +static void dbfs_open_res (const struct evsql_result_info *res, void *arg) { + struct dbfs_fileop *fop = arg; + int err; + + // check the results + if ((err = _dbfs_check_res(res, 1, 2))) + SERROR(err = (err == 1 ? ENOENT : EIO)); + + const char *type; + + // extract the data + if (0 + || evsql_result_string(res, 0, 0, &type, 0 ) // inodes.type + || evsql_result_uint32(res, 0, 1, &fop->lo_fd, 0 ) // fd + ) + SERROR(err = EIO); + + // is it a dir? + if (_dbfs_mode(type) != S_IFREG) + EERROR(err = ENOENT, "wrong type: %s", type); + + INFO("[dbfs.open %p:%p] -> ino=%lu, type=%s", fop, fop->base.req, (unsigned long int) fop->base.ino, type); + + // open_fn done, do the open_reply + if ((err = dbfs_op_open_reply(&fop->base))) + goto error; + + // success, fallthrough for evsql_result_free + err = 0; + +error: + if (err) + // fail it + dbfs_op_fail(&fop->base, err); + + // free + evsql_result_free(res); +} + +static void dbfs_fileop_open (struct dbfs_op *op_base) { + struct dbfs_fileop *fop = (struct dbfs_fileop *) op_base; + struct dbfs *ctx = fuse_req_userdata(fop->base.req); + int err; + + // make sure the file actually exists + const char *sql = + "SELECT" + " inodes.type, lo_open(inodes.data, $1::int4) AS fd" + " FROM inodes" + " WHERE inodes.ino = $2::int4"; + + static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) { + EVSQL_PARAM ( UINT32 ), + EVSQL_PARAM ( UINT32 ), + + EVSQL_PARAMS_END + }; + + // build params + if (0 + || evsql_param_uint32(¶ms, 0, INV_READ | INV_WRITE) + || evsql_param_uint32(¶ms, 1, fop->base.ino) + ) + SERROR(err = EIO); + + // query + if (evsql_query_params(ctx->db, fop->base.trans, sql, ¶ms, dbfs_open_res, fop) == NULL) + SERROR(err = EIO); + + // ok, wait for the info results + return; + +error: + // fail it + dbfs_op_fail(&fop->base, err); +} + +void dbfs_open (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi) { + struct dbfs *ctx = fuse_req_userdata(req); + struct dbfs_fileop *fop = NULL; + int err; + + // allocate it + if ((fop = calloc(1, sizeof(*fop))) == NULL && (err = EIO)) + ERROR("calloc"); + + // do the op_open + if ((err = dbfs_op_open(ctx, &fop->base, req, ino, fi, _dbfs_fileop_free, dbfs_fileop_open))) + ERROR("dbfs_op_open"); + + // log + INFO("[dbfs.open %p:%p] ino=%lu, fi->flags=%04X", fop, req, ino, fi->flags); + + // wait + return; + +error: + if (fop) { + // we can fail normally + dbfs_op_fail(&fop->base, err); + + } else { + // must error out manually as we couldn't alloc the context + if ((err = fuse_reply_err(req, err))) + EWARNING(err, "fuse_reply_err"); + } +} + +void dbfs_read_res (const struct evsql_result_info *res, void *arg) { + struct dbfs_fileop *fop = arg; + int err; + const char *buf; + size_t size; + + // check the results + if ((err = _dbfs_check_res(res, 1, 1)) < 0) + SERROR(err = EIO); + + // get the data + if (evsql_result_buf(res, 0, 0, &buf, &size, 0)) + SERROR(err = EIO); + + INFO("[dbfs.read %p:%p] -> size=%zu", fop, fop->base.req, size); + + // send it + if ((err = fuse_reply_buf(fop->base.req, buf, size))) + EERROR(err, "fuse_reply_buf"); + + // ok, req handled + if ((err = dbfs_op_req_done(&fop->base))) + goto error; + + // good, fallthrough + err = 0; + +error: + if (err) + dbfs_op_fail(&fop->base, err); + + // free + evsql_result_free(res); +} + +void dbfs_read (struct fuse_req *req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { + struct dbfs *ctx = fuse_req_userdata(req); + struct dbfs_fileop *fop; + int err; + + // get the op + if ((fop = (struct dbfs_fileop *) dbfs_op_req(req, ino, fi)) == NULL) + return; + + // log + INFO("[dbfs.read %p:%p] ino=%lu, size=%zu, off=%lu, fi->flags=%04X", fop, req, ino, size, off, fi->flags); + + // query + const char *sql = + "SELECT" + " lo_pread($1::int4, $2::int4, $3::int4)"; + + static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) { + EVSQL_PARAM ( UINT32 ), // fd + EVSQL_PARAM ( UINT32 ), // len + EVSQL_PARAM ( UINT32 ), // off + + EVSQL_PARAMS_END + }; + + // build params + if (0 + || evsql_param_uint32(¶ms, 0, fop->lo_fd) + || evsql_param_uint32(¶ms, 1, size) + || evsql_param_uint32(¶ms, 2, off) + ) + SERROR(err = EIO); + + // query + if (evsql_query_params(ctx->db, fop->base.trans, sql, ¶ms, dbfs_read_res, fop) == NULL) + SERROR(err = EIO); + + // ok, wait for the info results + return; + +error: + // fail it + dbfs_op_fail(&fop->base, err); +} + +void dbfs_write (struct fuse_req *req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info *fi) { + +} + +void dbfs_flush (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi) { + struct dbfs_fileop *fop; + int err; + + // get the fop + if ((fop = (struct dbfs_fileop *) dbfs_op_req(req, ino, fi)) == NULL) + return; + + // log + INFO("[dbfs.flush %p:%p] ino=%lu", fop, req, ino); + + // and reply... + if ((err = fuse_reply_err(req, 0))) + EWARNING(err, "fuse_reply_err"); + + // done + if ((err = dbfs_op_req_done(&fop->base))) + goto error; + + // good + return; + +error: + dbfs_op_fail(&fop->base, err); +} + +void dbfs_release (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi) { + // just passthrough to dbfs_op + // the lo_fd will be closed automatically + dbfs_op_release(req, ino, fi); +} diff -r 5de62ca9a5aa -r d8fabd347a8e src/dbfs/op_base.h --- a/src/dbfs/op_base.h Thu Oct 16 22:04:53 2008 +0300 +++ b/src/dbfs/op_base.h Thu Oct 16 22:56:29 2008 +0300 @@ -73,6 +73,8 @@ * Lookup the op for the given fi, validate params, and assign the new req. * * In case the op failed previously, this will error the req and return NULL, indicating that the req has been handled. + * + * Repeat, if this returns NULL, consider req invalid. */ struct dbfs_op *dbfs_op_req (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi); diff -r 5de62ca9a5aa -r d8fabd347a8e src/dbfs/ops.h --- a/src/dbfs/ops.h Thu Oct 16 22:04:53 2008 +0300 +++ b/src/dbfs/ops.h Thu Oct 16 22:56:29 2008 +0300 @@ -16,4 +16,10 @@ void dbfs_readdir (struct fuse_req *req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi); void dbfs_releasedir (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi); +/* fileop.c */ +void dbfs_open (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi); +void dbfs_read (struct fuse_req *req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi); +void dbfs_flush (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi); +void dbfs_release (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi); + #endif /* DBFS_OPS_H */ diff -r 5de62ca9a5aa -r d8fabd347a8e src/evsql.h --- a/src/evsql.h Thu Oct 16 22:04:53 2008 +0300 +++ b/src/evsql.h Thu Oct 16 22:56:29 2008 +0300 @@ -231,6 +231,7 @@ // fetch the raw binary value from a result set, and return it via ptr // if size is nonzero, check that the size of the field data matches +int evsql_result_buf (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, size_t *size, int nullok); int evsql_result_binary (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, size_t size, int nullok); int evsql_result_string (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, int nullok); diff -r 5de62ca9a5aa -r d8fabd347a8e src/evsql/util.c --- a/src/evsql/util.c Thu Oct 16 22:04:53 2008 +0300 +++ b/src/evsql/util.c Thu Oct 16 22:56:29 2008 +0300 @@ -64,7 +64,7 @@ } } -int evsql_result_binary (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, size_t size, int nullok) { +int evsql_result_buf (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, size_t *size, int nullok) { *ptr = NULL; switch (res->evsql->type) { @@ -79,10 +79,8 @@ if (PQfformat(res->result.pq, col) != 1) ERROR("[%zu:%zu] PQfformat is not binary: %d", row, col, PQfformat(res->result.pq, col)); - if (size && PQgetlength(res->result.pq, row, col) != size) - ERROR("[%zu:%zu] field size mismatch: %zu -> %d", row, col, size, PQgetlength(res->result.pq, row, col)); - - *ptr = PQgetvalue(res->result.pq, row, col); + *size = PQgetlength(res->result.pq, row, col); + *ptr = PQgetvalue(res->result.pq, row, col); return 0; @@ -94,6 +92,21 @@ return -1; } +int evsql_result_binary (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, size_t size, int nullok) { + size_t real_size; + + if (evsql_result_buf(res, row, col, ptr, &real_size, nullok)) + goto error; + + if (size && real_size != size) + ERROR("[%zu:%zu] field size mismatch: %zu -> %zu", row, col, size, real_size); + + return 0; + +error: + return -1; +} + int evsql_result_string (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, int nullok) { return evsql_result_binary(res, row, col, ptr, 0, nullok); }