Sort ERRORS.
[netbsd-mini2440.git] / libexec / lfs_cleanerd / fdfs.c
blobf110293e7cbf469a5e0ab1d17e8fe52d08dbfd02
1 /* $NetBSD: fdfs.c,v 1.6 2008/04/28 20:23:04 martin Exp $ */
3 /*-
4 * Copyright (c) 2005 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Konrad E. Schroder <perseant@hhhh.org>.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Buffer cache routines for a file-descriptor backed filesystem.
34 * This is part of lfs_cleanerd so there is also a "segment pointer" that
35 * we can make buffers out of without duplicating memory or reading the data
36 * again.
39 #include <err.h>
40 #include <fcntl.h>
41 #include <time.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
47 #include <sys/syslog.h>
48 #include <sys/param.h>
49 #include <sys/mount.h>
50 #include <sys/stat.h>
52 #include "vnode.h"
53 #include "bufcache.h"
54 #include "fdfs.h"
55 #include "kernelops.h"
58 * Return a "vnode" interface to a given file descriptor.
60 struct uvnode *
61 fd_vget(int fd, int bsize, int segsize, int nseg)
63 struct fdfs *fs;
64 struct uvnode *vp;
65 int i;
67 fs = (struct fdfs *)malloc(sizeof(*fs));
68 if (fs == NULL)
69 return NULL;
70 if (segsize > 0) {
71 fs->fd_bufp = (struct fd_buf *)malloc(nseg *
72 sizeof(struct fd_buf));
73 if (fs->fd_bufp == NULL) {
74 free(fs);
75 return NULL;
77 for (i = 0; i < nseg; i++) {
78 fs->fd_bufp[i].start = 0x0;
79 fs->fd_bufp[i].end = 0x0;
80 fs->fd_bufp[i].buf = (char *)malloc(segsize);
81 if (fs->fd_bufp[i].buf == NULL) {
82 while (--i >= 0)
83 free(fs->fd_bufp[i].buf);
84 free(fs->fd_bufp);
85 free(fs);
86 return NULL;
89 } else
90 fs->fd_bufp = NULL;
92 fs->fd_fd = fd;
93 fs->fd_bufc = nseg;
94 fs->fd_bufi = 0;
95 fs->fd_bsize = bsize;
96 fs->fd_ssize = segsize;
98 vp = (struct uvnode *) malloc(sizeof(*vp));
99 if (vp == NULL) {
100 if (fs->fd_bufp) {
101 for (i = nseg - 1; i >= 0; i--)
102 free(fs->fd_bufp[i].buf);
103 free(fs->fd_bufp);
105 free(fs);
106 return NULL;
108 memset(vp, 0, sizeof(*vp));
109 vp->v_fd = fd;
110 vp->v_fs = fs;
111 vp->v_usecount = 0;
112 vp->v_strategy_op = fd_vop_strategy;
113 vp->v_bwrite_op = fd_vop_bwrite;
114 vp->v_bmap_op = fd_vop_bmap;
115 LIST_INIT(&vp->v_cleanblkhd);
116 LIST_INIT(&vp->v_dirtyblkhd);
117 vp->v_data = NULL;
119 return vp;
123 * Deallocate a vnode.
125 void
126 fd_reclaim(struct uvnode *vp)
128 int i;
129 struct ubuf *bp;
130 struct fdfs *fs;
132 while ((bp = LIST_FIRST(&vp->v_dirtyblkhd)) != NULL) {
133 bremfree(bp);
134 buf_destroy(bp);
136 while ((bp = LIST_FIRST(&vp->v_cleanblkhd)) != NULL) {
137 bremfree(bp);
138 buf_destroy(bp);
141 fs = (struct fdfs *)vp->v_fs;
142 for (i = 0; i < fs->fd_bufc; i++)
143 free(fs->fd_bufp[i].buf);
144 free(fs->fd_bufp);
145 free(fs);
146 memset(vp, 0, sizeof(vp));
150 * We won't be using that last segment after all.
152 void
153 fd_release(struct uvnode *vp)
155 --((struct fdfs *)vp->v_fs)->fd_bufi;
159 * Reset buffer pointer to first buffer.
161 void
162 fd_release_all(struct uvnode *vp)
164 ((struct fdfs *)vp->v_fs)->fd_bufi = 0;
168 * Prepare a segment buffer which we will expect to read from.
169 * We never increment fd_bufi unless we have succeeded to allocate the space,
170 * if necessary, and have read the segment.
173 fd_preload(struct uvnode *vp, daddr_t start)
175 struct fdfs *fs = (struct fdfs *)vp->v_fs;
176 struct fd_buf *t;
177 int r;
179 /* We might need to allocate more buffers. */
180 if (fs->fd_bufi == fs->fd_bufc) {
181 ++fs->fd_bufc;
182 syslog(LOG_DEBUG, "increasing number of segment buffers to %d",
183 fs->fd_bufc);
184 t = realloc(fs->fd_bufp, fs->fd_bufc * sizeof(struct fd_buf));
185 if (t == NULL) {
186 syslog(LOG_NOTICE, "failed resizing table to %d\n",
187 fs->fd_bufc);
188 return -1;
190 fs->fd_bufp = t;
191 fs->fd_bufp[fs->fd_bufi].start = 0x0;
192 fs->fd_bufp[fs->fd_bufi].end = 0x0;
193 fs->fd_bufp[fs->fd_bufi].buf = (char *)malloc(fs->fd_ssize);
194 if (fs->fd_bufp[fs->fd_bufi].buf == NULL) {
195 syslog(LOG_NOTICE, "failed to allocate buffer #%d\n",
196 fs->fd_bufc);
197 --fs->fd_bufc;
198 return -1;
202 /* Read the current buffer. */
203 fs->fd_bufp[fs->fd_bufi].start = start;
204 fs->fd_bufp[fs->fd_bufi].end = start + fs->fd_ssize / fs->fd_bsize;
206 if ((r = kops.ko_pread(fs->fd_fd, fs->fd_bufp[fs->fd_bufi].buf,
207 (size_t)fs->fd_ssize, start * fs->fd_bsize)) < 0) {
208 syslog(LOG_ERR, "preload to segment buffer %d", fs->fd_bufi);
209 return r;
212 fs->fd_bufi = fs->fd_bufi + 1;
213 return 0;
217 * Get a pointer to a block contained in one of the segment buffers,
218 * as if from bread() but avoiding the buffer cache.
220 char *
221 fd_ptrget(struct uvnode *vp, daddr_t bn)
223 int i;
224 struct fdfs *fs;
226 fs = (struct fdfs *)vp->v_fs;
227 for (i = 0; i < fs->fd_bufc; i++) {
228 if (bn >= fs->fd_bufp[i].start && bn < fs->fd_bufp[i].end) {
229 return fs->fd_bufp[i].buf +
230 (bn - fs->fd_bufp[i].start) * fs->fd_bsize;
233 return NULL;
237 * Strategy routine. We can read from the segment buffer if requested.
240 fd_vop_strategy(struct ubuf * bp)
242 struct fdfs *fs;
243 char *cp;
244 int count;
246 fs = (struct fdfs *)bp->b_vp->v_fs;
247 if (bp->b_flags & B_READ) {
248 if ((cp = fd_ptrget(bp->b_vp, bp->b_blkno)) != NULL) {
249 free(bp->b_data);
250 bp->b_data = cp;
251 bp->b_flags |= (B_DONTFREE | B_DONE);
252 return 0;
254 count = kops.ko_pread(bp->b_vp->v_fd, bp->b_data, bp->b_bcount,
255 bp->b_blkno * fs->fd_bsize);
256 if (count == bp->b_bcount)
257 bp->b_flags |= B_DONE;
258 } else {
259 count = kops.ko_pwrite(bp->b_vp->v_fd, bp->b_data, bp->b_bcount,
260 bp->b_blkno * fs->fd_bsize);
261 if (count == 0) {
262 perror("pwrite");
263 return -1;
265 bp->b_flags &= ~B_DELWRI;
266 reassignbuf(bp, bp->b_vp);
268 return 0;
272 * Delayed write.
275 fd_vop_bwrite(struct ubuf * bp)
277 bp->b_flags |= B_DELWRI;
278 reassignbuf(bp, bp->b_vp);
279 brelse(bp, 0);
280 return 0;
284 * Map lbn to disk address. Since we are using the file
285 * descriptor as the "disk", the disk address is meaningless
286 * and we just return the block address.
289 fd_vop_bmap(struct uvnode * vp, daddr_t lbn, daddr_t * daddrp)
291 *daddrp = lbn;
292 return 0;