1 /* $NetBSD: fdfs.c,v 1.6 2008/04/28 20:23:04 martin Exp $ */
4 * Copyright (c) 2005 The NetBSD Foundation, Inc.
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
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
47 #include <sys/syslog.h>
48 #include <sys/param.h>
49 #include <sys/mount.h>
55 #include "kernelops.h"
58 * Return a "vnode" interface to a given file descriptor.
61 fd_vget(int fd
, int bsize
, int segsize
, int nseg
)
67 fs
= (struct fdfs
*)malloc(sizeof(*fs
));
71 fs
->fd_bufp
= (struct fd_buf
*)malloc(nseg
*
72 sizeof(struct fd_buf
));
73 if (fs
->fd_bufp
== 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
) {
83 free(fs
->fd_bufp
[i
].buf
);
96 fs
->fd_ssize
= segsize
;
98 vp
= (struct uvnode
*) malloc(sizeof(*vp
));
101 for (i
= nseg
- 1; i
>= 0; i
--)
102 free(fs
->fd_bufp
[i
].buf
);
108 memset(vp
, 0, sizeof(*vp
));
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
);
123 * Deallocate a vnode.
126 fd_reclaim(struct uvnode
*vp
)
132 while ((bp
= LIST_FIRST(&vp
->v_dirtyblkhd
)) != NULL
) {
136 while ((bp
= LIST_FIRST(&vp
->v_cleanblkhd
)) != NULL
) {
141 fs
= (struct fdfs
*)vp
->v_fs
;
142 for (i
= 0; i
< fs
->fd_bufc
; i
++)
143 free(fs
->fd_bufp
[i
].buf
);
146 memset(vp
, 0, sizeof(vp
));
150 * We won't be using that last segment after all.
153 fd_release(struct uvnode
*vp
)
155 --((struct fdfs
*)vp
->v_fs
)->fd_bufi
;
159 * Reset buffer pointer to first buffer.
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
;
179 /* We might need to allocate more buffers. */
180 if (fs
->fd_bufi
== fs
->fd_bufc
) {
182 syslog(LOG_DEBUG
, "increasing number of segment buffers to %d",
184 t
= realloc(fs
->fd_bufp
, fs
->fd_bufc
* sizeof(struct fd_buf
));
186 syslog(LOG_NOTICE
, "failed resizing table to %d\n",
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",
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
);
212 fs
->fd_bufi
= fs
->fd_bufi
+ 1;
217 * Get a pointer to a block contained in one of the segment buffers,
218 * as if from bread() but avoiding the buffer cache.
221 fd_ptrget(struct uvnode
*vp
, daddr_t bn
)
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
;
237 * Strategy routine. We can read from the segment buffer if requested.
240 fd_vop_strategy(struct ubuf
* bp
)
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
) {
251 bp
->b_flags
|= (B_DONTFREE
| B_DONE
);
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
;
259 count
= kops
.ko_pwrite(bp
->b_vp
->v_fd
, bp
->b_data
, bp
->b_bcount
,
260 bp
->b_blkno
* fs
->fd_bsize
);
265 bp
->b_flags
&= ~B_DELWRI
;
266 reassignbuf(bp
, bp
->b_vp
);
275 fd_vop_bwrite(struct ubuf
* bp
)
277 bp
->b_flags
|= B_DELWRI
;
278 reassignbuf(bp
, bp
->b_vp
);
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
)