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