]> mj.ucw.cz Git - libucw.git/blob - ucw/fb-param.c
514f987bb719729046a5fc16e1f1ba38a228233e
[libucw.git] / ucw / fb-param.c
1 /*
2  *      UCW Library -- FastIO on files with run-time parametrization
3  *
4  *      (c) 2007 Pavel Charvat <pchar@ucw.cz>
5  *      (c) 2007 Martin Mares <mj@ucw.cz>
6  *
7  *      This software may be freely distributed and used according to the terms
8  *      of the GNU Lesser General Public License.
9  */
10
11 #include "ucw/lib.h"
12 #include "ucw/conf.h"
13 #include "ucw/lfs.h"
14 #include "ucw/fastbuf.h"
15
16 #include <fcntl.h>
17 #include <stdio.h>
18
19 struct fb_params fbpar_def = {
20   .buffer_size = 65536,
21   .read_ahead = 1,
22   .write_back = 1,
23 };
24
25 static char *
26 fbpar_cf_commit(struct fb_params *p UNUSED)
27 {
28 #ifndef CONFIG_UCW_THREADS
29   if (p->type == FB_DIRECT)
30     return "Direct I/O is supported only with CONFIG_UCW_THREADS";
31 #endif
32 #ifndef CONFIG_DIRECT
33   if (p->type == FB_DIRECT)
34     return "Direct I/O is disabled";
35 #endif
36   return NULL;
37 }
38
39 struct cf_section fbpar_cf = {
40 # define F(x) PTR_TO(struct fb_params, x)
41   CF_TYPE(struct fb_params),
42   CF_COMMIT(fbpar_cf_commit),
43   CF_ITEMS {
44     CF_LOOKUP("Type", (int *)F(type), ((const char * const []){"std", "direct", "mmap", NULL})),
45     CF_UNS("BufSize", F(buffer_size)),
46     CF_UNS("KeepBackBuf", F(keep_back_buf)),
47     CF_UNS("ReadAhead", F(read_ahead)),
48     CF_UNS("WriteBack", F(write_back)),
49     CF_END
50   }
51 # undef F
52 };
53
54 static struct cf_section fbpar_global_cf = {
55   CF_ITEMS {
56     CF_SECTION("Defaults", &fbpar_def, &fbpar_cf),
57     CF_END
58   }
59 };
60
61 static void CONSTRUCTOR
62 fbpar_global_init(void)
63 {
64   cf_declare_section("FBParam", &fbpar_global_cf, 0);
65 }
66
67 static struct fastbuf *
68 bopen_fd_internal(int fd, struct fb_params *params, uns mode, const char *name)
69 {
70   char buf[32];
71   if (!name)
72     {
73       sprintf(buf, "fd%d", fd);
74       name = buf;
75     }
76   struct fastbuf *fb;
77   switch (params->type)
78     {
79 #ifdef CONFIG_DIRECT
80       case FB_DIRECT:
81         fb = fbdir_open_fd_internal(fd, name, params->asio,
82             params->buffer_size ? : fbpar_def.buffer_size,
83             params->read_ahead ? : fbpar_def.read_ahead,
84             params->write_back ? : fbpar_def.write_back);
85         if (!~mode && !fbdir_cheat && ((int)(mode = fcntl(fd, F_GETFL)) < 0 || fcntl(fd, F_SETFL, mode | O_DIRECT)) < 0)
86           msg(L_WARN, "Cannot set O_DIRECT on fd %d: %m", fd);
87         return fb;
88 #endif
89       case FB_STD:
90         fb = bfdopen_internal(fd, name,
91             params->buffer_size ? : fbpar_def.buffer_size);
92         if (params->keep_back_buf)
93           bconfig(fb, BCONFIG_KEEP_BACK_BUF, 1);
94         return fb;
95       case FB_MMAP:
96         if (!~mode && (int)(mode = fcntl(fd, F_GETFL)) < 0)
97           die("Cannot get flags of fd %d: %m", fd);
98         return bfmmopen_internal(fd, name, mode);
99       default:
100         ASSERT(0);
101     }
102 }
103
104 static struct fastbuf *
105 bopen_file_internal(const char *name, int mode, struct fb_params *params, int try)
106 {
107   if (!params)
108     params = &fbpar_def;
109 #ifdef CONFIG_DIRECT
110   if (params->type == FB_DIRECT && !fbdir_cheat)
111     mode |= O_DIRECT;
112 #endif
113   if (params->type == FB_MMAP && (mode & O_ACCMODE) == O_WRONLY)
114     mode = (mode & ~O_ACCMODE) | O_RDWR;
115   int fd = ucw_open(name, mode, 0666);
116   if (fd < 0)
117     if (try)
118       return NULL;
119     else
120       die("Unable to %s file %s: %m", (mode & O_CREAT) ? "create" : "open", name);
121   struct fastbuf *fb = bopen_fd_internal(fd, params, mode, name);
122   ASSERT(fb);
123   if (mode & O_APPEND)
124     bseek(fb, 0, SEEK_END);
125   return fb;
126 }
127
128 struct fastbuf *
129 bopen_file(const char *name, int mode, struct fb_params *params)
130 {
131   return bopen_file_internal(name, mode, params, 0);
132 }
133
134 struct fastbuf *
135 bopen_file_try(const char *name, int mode, struct fb_params *params)
136 {
137   return bopen_file_internal(name, mode, params, 1);
138 }
139
140 struct fastbuf *
141 bopen_fd_name(int fd, struct fb_params *params, const char *name)
142 {
143   return bopen_fd_internal(fd, params ? : &fbpar_def, ~0U, name);
144 }
145
146 /* Function for use by individual file back-ends */
147
148 void
149 bclose_file_helper(struct fastbuf *f, int fd, int is_temp_file)
150 {
151   switch (is_temp_file)
152     {
153     case 1:
154       if (unlink(f->name) < 0)
155         msg(L_ERROR, "unlink(%s): %m", f->name);
156     case 0:
157       if (close(fd))
158         die("close(%s): %m", f->name);
159     }
160 }
161
162 /* Compatibility wrappers */
163
164 struct fastbuf *
165 bopen_try(const char *name, uns mode, uns buflen)
166 {
167   return bopen_file_try(name, mode, &(struct fb_params){ .type = FB_STD, .buffer_size = buflen });
168 }
169
170 struct fastbuf *
171 bopen(const char *name, uns mode, uns buflen)
172 {
173   return bopen_file(name, mode, &(struct fb_params){ .type = FB_STD, .buffer_size = buflen });
174 }
175
176 struct fastbuf *
177 bfdopen(int fd, uns buflen)
178 {
179   return bopen_fd(fd, &(struct fb_params){ .type = FB_STD, .buffer_size = buflen });
180 }
181
182 struct fastbuf *
183 bfdopen_shared(int fd, uns buflen)
184 {
185   struct fastbuf *f = bfdopen(fd, buflen);
186   bconfig(f, BCONFIG_IS_TEMP_FILE, 2);
187   return f;
188 }