fdfs.c revision 1.4 1 1.4 christos /* $NetBSD: fdfs.c,v 1.4 2006/05/19 14:46:17 christos Exp $ */
2 1.1 perseant
3 1.1 perseant /*-
4 1.1 perseant * Copyright (c) 2005 The NetBSD Foundation, Inc.
5 1.1 perseant * All rights reserved.
6 1.1 perseant *
7 1.1 perseant * This code is derived from software contributed to The NetBSD Foundation
8 1.1 perseant * by Konrad E. Schroder <perseant (at) hhhh.org>.
9 1.1 perseant *
10 1.1 perseant * Redistribution and use in source and binary forms, with or without
11 1.1 perseant * modification, are permitted provided that the following conditions
12 1.1 perseant * are met:
13 1.1 perseant * 1. Redistributions of source code must retain the above copyright
14 1.1 perseant * notice, this list of conditions and the following disclaimer.
15 1.1 perseant * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 perseant * notice, this list of conditions and the following disclaimer in the
17 1.1 perseant * documentation and/or other materials provided with the distribution.
18 1.1 perseant * 3. All advertising materials mentioning features or use of this software
19 1.1 perseant * must display the following acknowledgement:
20 1.1 perseant * This product includes software developed by the NetBSD
21 1.1 perseant * Foundation, Inc. and its contributors.
22 1.1 perseant * 4. Neither the name of The NetBSD Foundation nor the names of its
23 1.1 perseant * contributors may be used to endorse or promote products derived
24 1.1 perseant * from this software without specific prior written permission.
25 1.1 perseant *
26 1.1 perseant * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 1.1 perseant * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 1.1 perseant * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 1.1 perseant * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 1.1 perseant * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 1.1 perseant * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 1.1 perseant * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 1.1 perseant * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 1.1 perseant * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 1.1 perseant * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 1.1 perseant * POSSIBILITY OF SUCH DAMAGE.
37 1.1 perseant */
38 1.1 perseant
39 1.1 perseant /*
40 1.1 perseant * Buffer cache routines for a file-descriptor backed filesystem.
41 1.1 perseant * This is part of lfs_cleanerd so there is also a "segment pointer" that
42 1.1 perseant * we can make buffers out of without duplicating memory or reading the data
43 1.1 perseant * again.
44 1.1 perseant */
45 1.1 perseant
46 1.1 perseant #include <err.h>
47 1.1 perseant #include <fcntl.h>
48 1.1 perseant #include <time.h>
49 1.1 perseant #include <stdio.h>
50 1.1 perseant #include <stdlib.h>
51 1.1 perseant #include <string.h>
52 1.1 perseant #include <unistd.h>
53 1.1 perseant
54 1.1 perseant #include <sys/syslog.h>
55 1.1 perseant #include <sys/param.h>
56 1.1 perseant #include <sys/mount.h>
57 1.1 perseant #include <sys/stat.h>
58 1.1 perseant
59 1.1 perseant #include "vnode.h"
60 1.1 perseant #include "bufcache.h"
61 1.1 perseant #include "fdfs.h"
62 1.1 perseant
63 1.1 perseant /*
64 1.1 perseant * Return a "vnode" interface to a given file descriptor.
65 1.1 perseant */
66 1.1 perseant struct uvnode *
67 1.1 perseant fd_vget(int fd, int bsize, int segsize, int nseg)
68 1.1 perseant {
69 1.1 perseant struct fdfs *fs;
70 1.1 perseant struct uvnode *vp;
71 1.1 perseant int i;
72 1.1 perseant
73 1.1 perseant fs = (struct fdfs *)malloc(sizeof(*fs));
74 1.1 perseant if (fs == NULL)
75 1.1 perseant return NULL;
76 1.1 perseant if (segsize > 0) {
77 1.1 perseant fs->fd_bufp = (struct fd_buf *)malloc(nseg *
78 1.1 perseant sizeof(struct fd_buf));
79 1.1 perseant if (fs->fd_bufp == NULL) {
80 1.1 perseant free(fs);
81 1.1 perseant return NULL;
82 1.1 perseant }
83 1.1 perseant for (i = 0; i < nseg; i++) {
84 1.1 perseant fs->fd_bufp[i].start = 0x0;
85 1.1 perseant fs->fd_bufp[i].end = 0x0;
86 1.1 perseant fs->fd_bufp[i].buf = (char *)malloc(segsize);
87 1.1 perseant if (fs->fd_bufp[i].buf == NULL) {
88 1.1 perseant while (--i >= 0)
89 1.1 perseant free(fs->fd_bufp[i].buf);
90 1.1 perseant free(fs->fd_bufp);
91 1.1 perseant free(fs);
92 1.1 perseant return NULL;
93 1.1 perseant }
94 1.1 perseant }
95 1.1 perseant } else
96 1.1 perseant fs->fd_bufp = NULL;
97 1.1 perseant
98 1.1 perseant fs->fd_fd = fd;
99 1.1 perseant fs->fd_bufc = nseg;
100 1.1 perseant fs->fd_bufi = 0;
101 1.1 perseant fs->fd_bsize = bsize;
102 1.1 perseant fs->fd_ssize = segsize;
103 1.1 perseant
104 1.1 perseant vp = (struct uvnode *) malloc(sizeof(*vp));
105 1.3 perseant if (vp == NULL) {
106 1.4 christos if (fs->fd_bufp) {
107 1.4 christos for (i = nseg - 1; i >= 0; i--)
108 1.4 christos free(fs->fd_bufp[i].buf);
109 1.4 christos free(fs->fd_bufp);
110 1.4 christos }
111 1.3 perseant free(fs);
112 1.3 perseant return NULL;
113 1.3 perseant }
114 1.1 perseant memset(vp, 0, sizeof(*vp));
115 1.1 perseant vp->v_fd = fd;
116 1.1 perseant vp->v_fs = fs;
117 1.1 perseant vp->v_usecount = 0;
118 1.1 perseant vp->v_strategy_op = fd_vop_strategy;
119 1.1 perseant vp->v_bwrite_op = fd_vop_bwrite;
120 1.1 perseant vp->v_bmap_op = fd_vop_bmap;
121 1.1 perseant LIST_INIT(&vp->v_cleanblkhd);
122 1.1 perseant LIST_INIT(&vp->v_dirtyblkhd);
123 1.1 perseant vp->v_data = NULL;
124 1.1 perseant
125 1.1 perseant return vp;
126 1.1 perseant }
127 1.1 perseant
128 1.1 perseant /*
129 1.1 perseant * Deallocate a vnode.
130 1.1 perseant */
131 1.1 perseant void
132 1.1 perseant fd_reclaim(struct uvnode *vp)
133 1.1 perseant {
134 1.1 perseant int i;
135 1.1 perseant struct ubuf *bp;
136 1.1 perseant struct fdfs *fs;
137 1.1 perseant
138 1.2 christos while ((bp = LIST_FIRST(&vp->v_dirtyblkhd)) != NULL) {
139 1.1 perseant bremfree(bp);
140 1.1 perseant buf_destroy(bp);
141 1.1 perseant }
142 1.2 christos while ((bp = LIST_FIRST(&vp->v_cleanblkhd)) != NULL) {
143 1.1 perseant bremfree(bp);
144 1.1 perseant buf_destroy(bp);
145 1.1 perseant }
146 1.1 perseant
147 1.1 perseant fs = (struct fdfs *)vp->v_fs;
148 1.1 perseant for (i = 0; i < fs->fd_bufc; i++)
149 1.1 perseant free(fs->fd_bufp[i].buf);
150 1.1 perseant free(fs->fd_bufp);
151 1.1 perseant free(fs);
152 1.1 perseant memset(vp, 0, sizeof(vp));
153 1.1 perseant }
154 1.1 perseant
155 1.1 perseant /*
156 1.1 perseant * We won't be using that last segment after all.
157 1.1 perseant */
158 1.1 perseant void
159 1.1 perseant fd_release(struct uvnode *vp)
160 1.1 perseant {
161 1.1 perseant --((struct fdfs *)vp->v_fs)->fd_bufi;
162 1.1 perseant }
163 1.1 perseant
164 1.1 perseant /*
165 1.1 perseant * Reset buffer pointer to first buffer.
166 1.1 perseant */
167 1.1 perseant void
168 1.1 perseant fd_release_all(struct uvnode *vp)
169 1.1 perseant {
170 1.1 perseant ((struct fdfs *)vp->v_fs)->fd_bufi = 0;
171 1.1 perseant }
172 1.1 perseant
173 1.1 perseant /*
174 1.1 perseant * Prepare a segment buffer which we will expect to read from.
175 1.3 perseant * We never increment fd_bufi unless we have succeeded to allocate the space,
176 1.3 perseant * if necessary, and have read the segment.
177 1.1 perseant */
178 1.1 perseant int
179 1.1 perseant fd_preload(struct uvnode *vp, daddr_t start)
180 1.1 perseant {
181 1.1 perseant struct fdfs *fs = (struct fdfs *)vp->v_fs;
182 1.1 perseant struct fd_buf *t;
183 1.1 perseant int r;
184 1.1 perseant
185 1.1 perseant /* We might need to allocate more buffers. */
186 1.1 perseant if (fs->fd_bufi == fs->fd_bufc) {
187 1.3 perseant ++fs->fd_bufc;
188 1.1 perseant syslog(LOG_DEBUG, "increasing number of segment buffers to %d",
189 1.1 perseant fs->fd_bufc);
190 1.1 perseant t = realloc(fs->fd_bufp, fs->fd_bufc * sizeof(struct fd_buf));
191 1.3 perseant if (t == NULL) {
192 1.3 perseant syslog(LOG_NOTICE, "failed resizing table to %d\n",
193 1.3 perseant fs->fd_bufc);
194 1.1 perseant return -1;
195 1.3 perseant }
196 1.1 perseant fs->fd_bufp = t;
197 1.1 perseant fs->fd_bufp[fs->fd_bufi].start = 0x0;
198 1.1 perseant fs->fd_bufp[fs->fd_bufi].end = 0x0;
199 1.1 perseant fs->fd_bufp[fs->fd_bufi].buf = (char *)malloc(fs->fd_ssize);
200 1.1 perseant if (fs->fd_bufp[fs->fd_bufi].buf == NULL) {
201 1.3 perseant syslog(LOG_NOTICE, "failed to allocate buffer #%d\n",
202 1.3 perseant fs->fd_bufc);
203 1.1 perseant --fs->fd_bufc;
204 1.3 perseant return -1;
205 1.1 perseant }
206 1.1 perseant }
207 1.1 perseant
208 1.1 perseant /* Read the current buffer. */
209 1.1 perseant fs->fd_bufp[fs->fd_bufi].start = start;
210 1.1 perseant fs->fd_bufp[fs->fd_bufi].end = start + fs->fd_ssize / fs->fd_bsize;
211 1.1 perseant
212 1.1 perseant if ((r = pread(fs->fd_fd, fs->fd_bufp[fs->fd_bufi].buf,
213 1.1 perseant (size_t)fs->fd_ssize, start * fs->fd_bsize)) < 0) {
214 1.1 perseant syslog(LOG_ERR, "preload to segment buffer %d", fs->fd_bufi);
215 1.1 perseant return r;
216 1.1 perseant }
217 1.1 perseant
218 1.1 perseant fs->fd_bufi = fs->fd_bufi + 1;
219 1.1 perseant return 0;
220 1.1 perseant }
221 1.1 perseant
222 1.1 perseant /*
223 1.1 perseant * Get a pointer to a block contained in one of the segment buffers,
224 1.1 perseant * as if from bread() but avoiding the buffer cache.
225 1.1 perseant */
226 1.1 perseant char *
227 1.1 perseant fd_ptrget(struct uvnode *vp, daddr_t bn)
228 1.1 perseant {
229 1.1 perseant int i;
230 1.1 perseant struct fdfs *fs;
231 1.1 perseant
232 1.1 perseant fs = (struct fdfs *)vp->v_fs;
233 1.1 perseant for (i = 0; i < fs->fd_bufc; i++) {
234 1.1 perseant if (bn >= fs->fd_bufp[i].start && bn < fs->fd_bufp[i].end) {
235 1.1 perseant return fs->fd_bufp[i].buf +
236 1.1 perseant (bn - fs->fd_bufp[i].start) * fs->fd_bsize;
237 1.1 perseant }
238 1.1 perseant }
239 1.1 perseant return NULL;
240 1.1 perseant }
241 1.1 perseant
242 1.1 perseant /*
243 1.1 perseant * Strategy routine. We can read from the segment buffer if requested.
244 1.1 perseant */
245 1.1 perseant int
246 1.1 perseant fd_vop_strategy(struct ubuf * bp)
247 1.1 perseant {
248 1.1 perseant struct fdfs *fs;
249 1.1 perseant char *cp;
250 1.1 perseant int count;
251 1.1 perseant
252 1.1 perseant fs = (struct fdfs *)bp->b_vp->v_fs;
253 1.1 perseant if (bp->b_flags & B_READ) {
254 1.1 perseant if ((cp = fd_ptrget(bp->b_vp, bp->b_blkno)) != NULL) {
255 1.1 perseant free(bp->b_data);
256 1.1 perseant bp->b_data = cp;
257 1.1 perseant bp->b_flags |= (B_DONTFREE | B_DONE);
258 1.1 perseant return 0;
259 1.1 perseant }
260 1.1 perseant count = pread(bp->b_vp->v_fd, bp->b_data, bp->b_bcount,
261 1.1 perseant bp->b_blkno * fs->fd_bsize);
262 1.1 perseant if (count == bp->b_bcount)
263 1.1 perseant bp->b_flags |= B_DONE;
264 1.1 perseant } else {
265 1.1 perseant count = pwrite(bp->b_vp->v_fd, bp->b_data, bp->b_bcount,
266 1.1 perseant bp->b_blkno * fs->fd_bsize);
267 1.1 perseant if (count == 0) {
268 1.1 perseant perror("pwrite");
269 1.1 perseant return -1;
270 1.1 perseant }
271 1.1 perseant bp->b_flags &= ~B_DELWRI;
272 1.1 perseant reassignbuf(bp, bp->b_vp);
273 1.1 perseant }
274 1.1 perseant return 0;
275 1.1 perseant }
276 1.1 perseant
277 1.1 perseant /*
278 1.1 perseant * Delayed write.
279 1.1 perseant */
280 1.1 perseant int
281 1.1 perseant fd_vop_bwrite(struct ubuf * bp)
282 1.1 perseant {
283 1.1 perseant bp->b_flags |= B_DELWRI;
284 1.1 perseant reassignbuf(bp, bp->b_vp);
285 1.1 perseant brelse(bp);
286 1.1 perseant return 0;
287 1.1 perseant }
288 1.1 perseant
289 1.1 perseant /*
290 1.1 perseant * Map lbn to disk address. Since we are using the file
291 1.1 perseant * descriptor as the "disk", the disk address is meaningless
292 1.1 perseant * and we just return the block address.
293 1.1 perseant */
294 1.1 perseant int
295 1.1 perseant fd_vop_bmap(struct uvnode * vp, daddr_t lbn, daddr_t * daddrp)
296 1.1 perseant {
297 1.1 perseant *daddrp = lbn;
298 1.1 perseant return 0;
299 1.1 perseant }
300