Home | History | Annotate | Line # | Download | only in lfs_cleanerd
fdfs.c revision 1.8.2.1
      1 /* $NetBSD: fdfs.c,v 1.8.2.1 2012/04/17 00:05:36 yamt Exp $	 */
      2 
      3 /*-
      4  * Copyright (c) 2005 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Konrad E. Schroder <perseant (at) hhhh.org>.
      9  *
     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.
     18  *
     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.
     30  */
     31 
     32 /*
     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.
     37  */
     38 
     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>
     46 
     47 #include <sys/syslog.h>
     48 #include <sys/param.h>
     49 #include <sys/mount.h>
     50 #include <sys/stat.h>
     51 
     52 #include "vnode.h"
     53 #include "bufcache.h"
     54 #include "fdfs.h"
     55 #include "kernelops.h"
     56 
     57 /*
     58  * Return a "vnode" interface to a given file descriptor.
     59  */
     60 struct uvnode *
     61 fd_vget(int fd, int bsize, int segsize, int nseg)
     62 {
     63 	struct fdfs *fs;
     64 	struct uvnode *vp;
     65 	int i;
     66 
     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;
     76 		}
     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;
     87 			}
     88 		}
     89 	} else
     90 		fs->fd_bufp = NULL;
     91 
     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;
     97 
     98 	vp = (struct uvnode *) malloc(sizeof(*vp));
     99 	if (vp == NULL) {
    100 		if (fs->fd_bufp) {
    101 			for (i = 0; i < nseg; i++)
    102 				free(fs->fd_bufp[i].buf);
    103 			free(fs->fd_bufp);
    104 		}
    105 		free(fs);
    106 		return NULL;
    107 	}
    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;
    118 
    119 	return vp;
    120 }
    121 
    122 /*
    123  * Deallocate a vnode.
    124  */
    125 void
    126 fd_reclaim(struct uvnode *vp)
    127 {
    128 	int i;
    129 	struct ubuf *bp;
    130 	struct fdfs *fs;
    131 
    132 	while ((bp = LIST_FIRST(&vp->v_dirtyblkhd)) != NULL) {
    133 		bremfree(bp);
    134 		buf_destroy(bp);
    135 	}
    136 	while ((bp = LIST_FIRST(&vp->v_cleanblkhd)) != NULL) {
    137 		bremfree(bp);
    138 		buf_destroy(bp);
    139 	}
    140 
    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));
    147 }
    148 
    149 /*
    150  * We won't be using that last segment after all.
    151  */
    152 void
    153 fd_release(struct uvnode *vp)
    154 {
    155 	--((struct fdfs *)vp->v_fs)->fd_bufi;
    156 }
    157 
    158 /*
    159  * Reset buffer pointer to first buffer.
    160  */
    161 void
    162 fd_release_all(struct uvnode *vp)
    163 {
    164 	((struct fdfs *)vp->v_fs)->fd_bufi = 0;
    165 }
    166 
    167 /*
    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.
    171  */
    172 int
    173 fd_preload(struct uvnode *vp, daddr_t start)
    174 {
    175 	struct fdfs *fs = (struct fdfs *)vp->v_fs;
    176 	struct fd_buf *t;
    177 	int r;
    178 
    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;
    189 		}
    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;
    199 		}
    200 	}
    201 
    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;
    205 
    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;
    210 	}
    211 
    212 	fs->fd_bufi = fs->fd_bufi + 1;
    213 	return 0;
    214 }
    215 
    216 /*
    217  * Get a pointer to a block contained in one of the segment buffers,
    218  * as if from bread() but avoiding the buffer cache.
    219  */
    220 char *
    221 fd_ptrget(struct uvnode *vp, daddr_t bn)
    222 {
    223 	int i;
    224 	struct fdfs *fs;
    225 
    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;
    231 		}
    232 	}
    233 	return NULL;
    234 }
    235 
    236 /*
    237  * Strategy routine.  We can read from the segment buffer if requested.
    238  */
    239 int
    240 fd_vop_strategy(struct ubuf * bp)
    241 {
    242 	struct fdfs *fs;
    243 	char *cp;
    244 	int count;
    245 
    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;
    253 		}
    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;
    264 		}
    265 		bp->b_flags &= ~B_DELWRI;
    266 		reassignbuf(bp, bp->b_vp);
    267 	}
    268 	return 0;
    269 }
    270 
    271 /*
    272  * Delayed write.
    273  */
    274 int
    275 fd_vop_bwrite(struct ubuf * bp)
    276 {
    277 	bp->b_flags |= B_DELWRI;
    278 	reassignbuf(bp, bp->b_vp);
    279 	brelse(bp, 0);
    280 	return 0;
    281 }
    282 
    283 /*
    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.
    287  */
    288 int
    289 fd_vop_bmap(struct uvnode * vp, daddr_t lbn, daddr_t * daddrp)
    290 {
    291 	*daddrp = lbn;
    292 	return 0;
    293 }
    294