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