X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;ds=sidebyside;f=lib%2Ffb-param.c;h=854ba78a78632e950ea6a5efe518a16a2d96ccaf;hb=c4bf633211b0424492b5a3937d6a6d2e0d79a4cf;hp=56f9b3f9e8d1ce57cf8f704c85e4fbf4d7242641;hpb=2c9aa505622e524dd4fa031981da1b432c8fadef;p=libucw.git diff --git a/lib/fb-param.c b/lib/fb-param.c index 56f9b3f9..854ba78a 100644 --- a/lib/fb-param.c +++ b/lib/fb-param.c @@ -2,6 +2,7 @@ * UCW Library -- FastIO on files with run-time parametrization * * (c) 2007 Pavel Charvat + * (c) 2007 Martin Mares * * This software may be freely distributed and used according to the terms * of the GNU Lesser General Public License. @@ -9,19 +10,38 @@ #include "lib/lib.h" #include "lib/conf.h" +#include "lib/lfs.h" #include "lib/fastbuf.h" -static struct fb_params fbpar_defaults = { +#include +#include + +struct fb_params fbpar_def = { .buffer_size = 65536, -}; + .read_ahead = 1, + .write_back = 1, +}; + +static char * +fbpar_cf_commit(struct fb_params *p UNUSED) +{ +#ifndef CONFIG_UCW_THREADS + if (p->type == FB_DIRECT) + return "Direct I/O is supported only with CONFIG_UCW_THREADS"; +#endif + return NULL; +} struct cf_section fbpar_cf = { # define F(x) PTR_TO(struct fb_params, x) CF_TYPE(struct fb_params), + CF_COMMIT(fbpar_cf_commit), CF_ITEMS { - // FIXME - CF_UNS("DirectIO", F(odirect)), + CF_LOOKUP("Type", (int *)F(type), ((char *[]){"std", "direct", "mmap", NULL})), CF_UNS("BufSize", F(buffer_size)), + CF_UNS("KeepBackBuf", F(keep_back_buf)), + CF_UNS("ReadAhead", F(read_ahead)), + CF_UNS("WriteBack", F(write_back)), CF_END } # undef F @@ -29,7 +49,7 @@ struct cf_section fbpar_cf = { static struct cf_section fbpar_global_cf = { CF_ITEMS { - CF_SECTION("Defaults", &fbpar_defaults, &fbpar_cf), + CF_SECTION("Defaults", &fbpar_def, &fbpar_cf), CF_END } }; @@ -40,42 +60,125 @@ fbpar_global_init(void) cf_declare_section("FBParam", &fbpar_global_cf, 0); } +static struct fastbuf * +bopen_fd_internal(int fd, struct fb_params *params, uns mode, const char *name) +{ + char buf[32]; + if (!name) + { + sprintf(buf, "fd%d", fd); + name = buf; + } + struct fastbuf *fb; + switch (params->type) + { +#ifdef CONFIG_UCW_THREADS + case FB_DIRECT: + fb = fbdir_open_fd_internal(fd, name, params->asio, + params->buffer_size ? : fbpar_def.buffer_size, + params->read_ahead ? : fbpar_def.read_ahead, + params->write_back ? : fbpar_def.write_back); + if (!~mode && !fbdir_cheat && ((int)(mode = fcntl(fd, F_GETFL)) < 0 || fcntl(fd, F_SETFL, mode | O_DIRECT)) < 0) + msg(L_WARN, "Cannot set O_DIRECT on fd %d: %m", fd); + return fb; +#endif + case FB_STD: + fb = bfdopen_internal(fd, name, + params->buffer_size ? : fbpar_def.buffer_size); + if (params->keep_back_buf) + bconfig(fb, BCONFIG_KEEP_BACK_BUF, 1); + return fb; + case FB_MMAP: + if (!~mode && (int)(mode = fcntl(fd, F_GETFL)) < 0) + die("Cannot get flags of fd %d: %m", fd); + return bfmmopen_internal(fd, name, mode); + default: + ASSERT(0); + } +} + +static struct fastbuf * +bopen_file_internal(const char *name, int mode, struct fb_params *params, int try) +{ + if (!params) + params = &fbpar_def; +#ifdef CONFIG_UCW_THREADS + if (params->type == FB_DIRECT && !fbdir_cheat) + mode |= O_DIRECT; +#endif + if (params->type == FB_MMAP && (mode & O_ACCMODE) == O_WRONLY) + mode = (mode & ~O_ACCMODE) | O_RDWR; + int fd = sh_open(name, mode, 0666); + if (fd < 0) + if (try) + return NULL; + else + die("Unable to %s file %s: %m", (mode & O_CREAT) ? "create" : "open", name); + struct fastbuf *fb = bopen_fd_internal(fd, params, mode, name); + ASSERT(fb); + if (mode & O_APPEND) + bseek(fb, 0, SEEK_END); + return fb; +} + +struct fastbuf * +bopen_file(const char *name, int mode, struct fb_params *params) +{ + return bopen_file_internal(name, mode, params, 0); +} + +struct fastbuf * +bopen_file_try(const char *name, int mode, struct fb_params *params) +{ + return bopen_file_internal(name, mode, params, 1); +} + +struct fastbuf * +bopen_fd(int fd, struct fb_params *params) +{ + return bopen_fd_internal(fd, params ? : &fbpar_def, ~0U, NULL); +} + +/* Function for use by individual file back-ends */ + +void +bclose_file_helper(struct fastbuf *f, int fd, int is_temp_file) +{ + switch (is_temp_file) + { + case 1: + if (unlink(f->name) < 0) + msg(L_ERROR, "unlink(%s): %m", f->name); + case 0: + if (close(fd)) + die("close(%s): %m", f->name); + } +} + +/* Compatibility wrappers */ + struct fastbuf * -fbpar_open(byte *name, int mode, struct fb_params *params) +bopen_try(const char *name, uns mode, uns buflen) { - params = params ? : &fbpar_defaults; - if (!params->odirect) - return bopen(name, mode, params->buffer_size); - else - return fbdir_open(name, mode, NULL); + return bopen_file_try(name, mode, &(struct fb_params){ .type = FB_STD, .buffer_size = buflen }); } struct fastbuf * -fbpar_open_try(byte *name, int mode, struct fb_params *params) +bopen(const char *name, uns mode, uns buflen) { - params = params ? : &fbpar_defaults; - if (!params->odirect) - return bopen_try(name, mode, params->buffer_size); - else - return fbdir_open_try(name, mode, NULL); + return bopen_file(name, mode, &(struct fb_params){ .type = FB_STD, .buffer_size = buflen }); } struct fastbuf * -fbpar_open_fd(int fd, struct fb_params *params) +bfdopen(int fd, uns buflen) { - params = params ? : &fbpar_defaults; - if (!params->odirect) - return bfdopen(fd, params->buffer_size); - else - return fbdir_open_fd(fd, NULL); + return bopen_fd(fd, &(struct fb_params){ .type = FB_STD, .buffer_size = buflen }); } struct fastbuf * -fbpar_open_tmp(struct fb_params *params) +bfdopen_shared(int fd, uns buflen) { - params = params ? : &fbpar_defaults; - if (!params->odirect) - return bopen_tmp(params->buffer_size); - else - return fbdir_open_tmp(NULL); + struct fastbuf *f = bfdopen(fd, buflen); + bconfig(f, BCONFIG_IS_TEMP_FILE, 2); + return f; }