From owner-svn-src-projects@FreeBSD.ORG Sat Mar 17 02:39:20 2012 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id BD8B0106564A; Sat, 17 Mar 2012 02:39:20 +0000 (UTC) (envelope-from gber@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id AB4FA8FC18; Sat, 17 Mar 2012 02:39:20 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q2H2dKkP046224; Sat, 17 Mar 2012 02:39:20 GMT (envelope-from gber@svn.freebsd.org) Received: (from gber@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q2H2dKT8046216; Sat, 17 Mar 2012 02:39:20 GMT (envelope-from gber@svn.freebsd.org) Message-Id: <201203170239.q2H2dKT8046216@svn.freebsd.org> From: Grzegorz Bernacki Date: Sat, 17 Mar 2012 02:39:20 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r233068 - in projects/nand/sys: conf fs/nandfs X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 17 Mar 2012 02:39:20 -0000 Author: gber Date: Sat Mar 17 02:39:20 2012 New Revision: 233068 URL: http://svn.freebsd.org/changeset/base/233068 Log: Add NANDFS This patch add core functionality of NANDFS. NANDFS is FS targeted mainly for NAND chips. It is based on NilFS, LogFS and UFS. Obtained from: Semihalf Supported by: FreeBSD Foundation, Juniper Networks Added: projects/nand/sys/fs/nandfs/ projects/nand/sys/fs/nandfs/bmap.c projects/nand/sys/fs/nandfs/bmap.h projects/nand/sys/fs/nandfs/nandfs.h projects/nand/sys/fs/nandfs/nandfs_alloc.c projects/nand/sys/fs/nandfs/nandfs_bmap.c projects/nand/sys/fs/nandfs/nandfs_buffer.c projects/nand/sys/fs/nandfs/nandfs_cpfile.c projects/nand/sys/fs/nandfs/nandfs_dat.c projects/nand/sys/fs/nandfs/nandfs_dir.c projects/nand/sys/fs/nandfs/nandfs_fs.h projects/nand/sys/fs/nandfs/nandfs_ifile.c projects/nand/sys/fs/nandfs/nandfs_mount.h projects/nand/sys/fs/nandfs/nandfs_segment.c projects/nand/sys/fs/nandfs/nandfs_subr.c projects/nand/sys/fs/nandfs/nandfs_subr.h projects/nand/sys/fs/nandfs/nandfs_sufile.c projects/nand/sys/fs/nandfs/nandfs_vfsops.c projects/nand/sys/fs/nandfs/nandfs_vnops.c Modified: projects/nand/sys/conf/files projects/nand/sys/conf/options Modified: projects/nand/sys/conf/files ============================================================================== --- projects/nand/sys/conf/files Sat Mar 17 02:05:33 2012 (r233067) +++ projects/nand/sys/conf/files Sat Mar 17 02:39:20 2012 (r233068) @@ -2134,6 +2134,19 @@ fs/msdosfs/msdosfs_iconv.c optional msdo fs/msdosfs/msdosfs_lookup.c optional msdosfs fs/msdosfs/msdosfs_vfsops.c optional msdosfs fs/msdosfs/msdosfs_vnops.c optional msdosfs +fs/nandfs/bmap.c optional nandfs +fs/nandfs/nandfs_alloc.c optional nandfs +fs/nandfs/nandfs_bmap.c optional nandfs +fs/nandfs/nandfs_buffer.c optional nandfs +fs/nandfs/nandfs_cpfile.c optional nandfs +fs/nandfs/nandfs_dat.c optional nandfs +fs/nandfs/nandfs_dir.c optional nandfs +fs/nandfs/nandfs_ifile.c optional nandfs +fs/nandfs/nandfs_segment.c optional nandfs +fs/nandfs/nandfs_subr.c optional nandfs +fs/nandfs/nandfs_sufile.c optional nandfs +fs/nandfs/nandfs_vfsops.c optional nandfs +fs/nandfs/nandfs_vnops.c optional nandfs fs/nfs/nfs_commonkrpc.c optional nfscl | nfsd fs/nfs/nfs_commonsubs.c optional nfscl | nfsd fs/nfs/nfs_commonport.c optional nfscl | nfsd Modified: projects/nand/sys/conf/options ============================================================================== --- projects/nand/sys/conf/options Sat Mar 17 02:05:33 2012 (r233067) +++ projects/nand/sys/conf/options Sat Mar 17 02:39:20 2012 (r233068) @@ -211,6 +211,7 @@ FDESCFS opt_dontuse.h FFS opt_dontuse.h HPFS opt_dontuse.h MSDOSFS opt_dontuse.h +NANDFS opt_dontuse.h NTFS opt_dontuse.h NULLFS opt_dontuse.h NWFS opt_dontuse.h Added: projects/nand/sys/fs/nandfs/bmap.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ projects/nand/sys/fs/nandfs/bmap.c Sat Mar 17 02:39:20 2012 (r233068) @@ -0,0 +1,621 @@ +/*- + * Copyright (c) 2012 Semihalf + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "nandfs_mount.h" +#include "nandfs.h" +#include "nandfs_subr.h" +#include "bmap.h" + +static int bmap_getlbns(struct nandfs_node *, nandfs_lbn_t, + struct nandfs_indir *, int *); + +int +bmap_lookup(struct nandfs_node *node, nandfs_lbn_t lblk, nandfs_daddr_t *vblk) +{ + struct nandfs_inode *ip; + struct nandfs_indir a[NIADDR + 1], *ap; + nandfs_daddr_t daddr; + struct buf *bp; + int error; + int num, *nump; + + DPRINTF(BMAP, ("%s: node %p lblk %jx enter\n", __func__, node, lblk)); + ip = &node->nn_inode; + + ap = a; + nump = # + + error = bmap_getlbns(node, lblk, ap, nump); + if (error) + return (error); + + if (num == 0) { + *vblk = ip->i_db[lblk]; + return (0); + } + + DPRINTF(BMAP, ("%s: node %p lblk=%jx trying ip->i_ib[%x]\n", __func__, + node, lblk, ap->in_off)); + daddr = ip->i_ib[ap->in_off]; + for (bp = NULL, ++ap; --num; ap++) { + if (daddr == 0) { + DPRINTF(BMAP, ("%s: node %p lblk=%jx returning with " + "vblk 0\n", __func__, node, lblk)); + *vblk = 0; + return (0); + } + if (ap->in_lbn == lblk) { + DPRINTF(BMAP, ("%s: node %p lblk=%jx ap->in_lbn=%jx " + "returning address of indirect block (%jx)\n", + __func__, node, lblk, ap->in_lbn, daddr)); + *vblk = daddr; + return (0); + } + + DPRINTF(BMAP, ("%s: node %p lblk=%jx reading block " + "ap->in_lbn=%jx\n", __func__, node, lblk, ap->in_lbn)); + + error = nandfs_bread_meta(node, ap->in_lbn, NOCRED, 0, &bp); + if (error) { + brelse(bp); + return (error); + } + + daddr = ((nandfs_daddr_t *)bp->b_data)[ap->in_off]; + brelse(bp); + } + + DPRINTF(BMAP, ("%s: node %p lblk=%jx returning with %jx\n", __func__, + node, lblk, daddr)); + *vblk = daddr; + + return (0); +} + +int +bmap_dirty_meta(struct nandfs_node *node, nandfs_lbn_t lblk, int force) +{ + struct nandfs_indir a[NIADDR+1], *ap; +#ifdef DEBUG + nandfs_daddr_t daddr; +#endif + struct buf *bp; + int error; + int num, *nump; + + DPRINTF(BMAP, ("%s: node %p lblk=%jx\n", __func__, node, lblk)); + + ap = a; + nump = # + + error = bmap_getlbns(node, lblk, ap, nump); + if (error) + return (error); + + /* + * Direct block, nothing to do + */ + if (num == 0) + return (0); + + DPRINTF(BMAP, ("%s: node %p reading blocks\n", __func__, node)); + + for (bp = NULL, ++ap; --num; ap++) { + error = nandfs_bread_meta(node, ap->in_lbn, NOCRED, 0, &bp); + if (error) { + brelse(bp); + return (error); + } + +#ifdef DEBUG + daddr = ((nandfs_daddr_t *)bp->b_data)[ap->in_off]; + MPASS(daddr != 0 || node->nn_ino == 3); +#endif + + error = nandfs_dirty_buf_meta(bp, force); + if (error) + return (error); + } + + return (0); +} + +int +bmap_insert_block(struct nandfs_node *node, nandfs_lbn_t lblk, + nandfs_daddr_t vblk) +{ + struct nandfs_inode *ip; + struct nandfs_indir a[NIADDR+1], *ap; + struct buf *bp; + nandfs_daddr_t daddr; + int error; + int num, *nump, i; + + DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx\n", __func__, node, lblk, + vblk)); + + ip = &node->nn_inode; + + ap = a; + nump = # + + error = bmap_getlbns(node, lblk, ap, nump); + if (error) + return (error); + + DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx got num=%d\n", __func__, + node, lblk, vblk, num)); + + if (num == 0) { + DPRINTF(BMAP, ("%s: node %p lblk=%jx direct block\n", __func__, + node, lblk)); + ip->i_db[lblk] = vblk; + return (0); + } + + DPRINTF(BMAP, ("%s: node %p lblk=%jx indirect block level %d\n", + __func__, node, lblk, ap->in_off)); + + if (num == 1) { + DPRINTF(BMAP, ("%s: node %p lblk=%jx indirect block: inserting " + "%jx as vblk for indirect block %d\n", __func__, node, + lblk, vblk, ap->in_off)); + ip->i_ib[ap->in_off] = vblk; + return (0); + } + + bp = NULL; + daddr = ip->i_ib[a[0].in_off]; + for (i = 1; i < num; i++) { + if (bp) + brelse(bp); + if (daddr == 0) { + DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx create " + "block %jx %d\n", __func__, node, lblk, vblk, + a[i].in_lbn, a[i].in_off)); + error = nandfs_bcreate_meta(node, a[i].in_lbn, NOCRED, + 0, &bp); + if (error) + return (error); + } else { + DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx read " + "block %jx %d\n", __func__, node, daddr, vblk, + a[i].in_lbn, a[i].in_off)); + error = nandfs_bread_meta(node, a[i].in_lbn, NOCRED, 0, &bp); + if (error) { + brelse(bp); + return (error); + } + } + daddr = ((nandfs_daddr_t *)bp->b_data)[a[i].in_off]; + } + i--; + + DPRINTF(BMAP, + ("%s: bmap node %p lblk=%jx vblk=%jx inserting vblk level %d at " + "offset %d at %jx\n", __func__, node, lblk, vblk, i, a[i].in_off, + daddr)); + + if (!bp) { + nandfs_error("%s: cannot find indirect block\n", __func__); + return (-1); + } + ((nandfs_daddr_t *)bp->b_data)[a[i].in_off] = vblk; + + error = nandfs_dirty_buf_meta(bp, 0); + if (error) { + nandfs_warning("%s: dirty failed buf: %p\n", __func__, bp); + return (error); + } + DPRINTF(BMAP, ("%s: exiting node %p lblk=%jx vblk=%jx\n", __func__, + node, lblk, vblk)); + + return (error); +} + +CTASSERT(NIADDR <= 3); +#define SINGLE 0 /* index of single indirect block */ +#define DOUBLE 1 /* index of double indirect block */ +#define TRIPLE 2 /* index of triple indirect block */ + +static __inline nandfs_lbn_t +lbn_offset(struct nandfs_device *fsdev, int level) +{ + nandfs_lbn_t res; + + for (res = 1; level > 0; level--) + res *= MNINDIR(fsdev); + return (res); +} + +static nandfs_lbn_t +blocks_inside(struct nandfs_device *fsdev, int level, struct nandfs_indir *nip) +{ + nandfs_lbn_t blocks; + + for (blocks = 1; level >= SINGLE; level--, nip++) { + MPASS(nip->in_off >= 0 && nip->in_off < MNINDIR(fsdev)); + blocks += nip->in_off * lbn_offset(fsdev, level); + } + + return (blocks); +} + +static int +bmap_truncate_indirect(struct nandfs_node *node, int level, nandfs_lbn_t *left, + int *cleaned, struct nandfs_indir *ap, struct nandfs_indir *fp, + nandfs_daddr_t *copy) +{ + struct buf *bp; + nandfs_lbn_t i, lbn, nlbn, factor, tosub; + struct nandfs_device *fsdev; + int error, lcleaned, modified; + + DPRINTF(BMAP, ("%s: node %p level %d left %jx\n", __func__, + node, level, *left)); + + fsdev = node->nn_nandfsdev; + + MPASS(ap->in_off >= 0 && ap->in_off < MNINDIR(fsdev)); + + factor = lbn_offset(fsdev, level); + lbn = ap->in_lbn; + + error = nandfs_bread_meta(node, lbn, NOCRED, 0, &bp); + if (error) { + brelse(bp); + return (error); + } + + bcopy(bp->b_data, copy, fsdev->nd_blocksize); + bqrelse(bp); + + modified = 0; + + i = ap->in_off; + + if (ap != fp) + ap++; + for (nlbn = lbn + 1 - i * factor; i >= 0 && *left > 0; i--, + nlbn += factor) { + lcleaned = 0; + + DPRINTF(BMAP, + ("%s: node %p i=%jx nlbn=%jx left=%jx ap=%p vblk %jx\n", + __func__, node, i, nlbn, *left, ap, copy[i])); + + if (copy[i] == 0) { + tosub = blocks_inside(fsdev, level - 1, ap); + if (tosub > *left) + tosub = 0; + + *left -= tosub; + } else { + if (level > SINGLE) { + if (ap == fp) + ap->in_lbn = nlbn; + + error = bmap_truncate_indirect(node, level - 1, + left, &lcleaned, ap, fp, + copy + MNINDIR(fsdev)); + if (error) + return (error); + } else { + error = nandfs_bdestroy(node, copy[i]); + if (error) + return (error); + lcleaned = 1; + *left -= 1; + } + } + + if (lcleaned) { + if (level > SINGLE) { + error = nandfs_vblock_end(fsdev, copy[i]); + if (error) + return (error); + } + copy[i] = 0; + modified++; + } + + ap = fp; + } + + if (i == -1) + *cleaned = 1; + + error = nandfs_bread_meta(node, lbn, NOCRED, 0, &bp); + if (error) { + brelse(bp); + return (error); + } + if (modified) + bcopy(copy, bp->b_data, fsdev->nd_blocksize); + + error = nandfs_dirty_buf_meta(bp, 0); + if (error) + return (error); + + return (error); +} + +int +bmap_truncate_mapping(struct nandfs_node *node, nandfs_lbn_t lastblk, + nandfs_lbn_t todo) +{ + struct nandfs_inode *ip; + struct nandfs_indir a[NIADDR + 1], f[NIADDR], *ap; + nandfs_daddr_t indir_lbn[NIADDR]; + nandfs_daddr_t *copy; + int error, level; + nandfs_lbn_t left, tosub; + struct nandfs_device *fsdev; + int cleaned, i; + int num, *nump; + + DPRINTF(BMAP, ("%s: node %p lastblk %jx truncating by %jx\n", __func__, + node, lastblk, todo)); + + ip = &node->nn_inode; + fsdev = node->nn_nandfsdev; + + ap = a; + nump = # + + error = bmap_getlbns(node, lastblk, ap, nump); + if (error) + return (error); + + indir_lbn[SINGLE] = -NDADDR; + indir_lbn[DOUBLE] = indir_lbn[SINGLE] - MNINDIR(fsdev) - 1; + indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - MNINDIR(fsdev) + * MNINDIR(fsdev) - 1; + + for (i = 0; i < NIADDR; i++) { + f[i].in_off = MNINDIR(fsdev) - 1; + f[i].in_lbn = 0xdeadbeef; + } + + left = todo; + +#ifdef DEBUG + a[num].in_off = -1; +#endif + + ap++; + num -= 2; + + if (num < 0) + goto direct; + + copy = malloc(MNINDIR(fsdev) * sizeof(nandfs_daddr_t) * (num + 1), + M_NANDFSTEMP, M_WAITOK); + + for (level = num; level >= SINGLE && left > 0; level--) { + cleaned = 0; + + if (ip->i_ib[level] == 0) { + tosub = blocks_inside(fsdev, level, ap); + if (tosub > left) + left = 0; + else + left -= tosub; + } else { + if (ap == f) + ap->in_lbn = indir_lbn[level]; + error = bmap_truncate_indirect(node, level, &left, + &cleaned, ap, f, copy); + if (error) { + nandfs_error("%s: error %d when truncate " + "at level %d\n", __func__, error, level); + return (error); + } + } + + if (cleaned) { + nandfs_vblock_end(fsdev, ip->i_ib[level]); + ip->i_ib[level] = 0; + } + + ap = f; + } + + free(copy, M_NANDFSTEMP); + +direct: + if (num < 0) + i = lastblk; + else + i = NDADDR - 1; + + for (; i >= 0 && left > 0; i--) { + if (ip->i_db[i] != 0) { + error = nandfs_bdestroy(node, ip->i_db[i]); + if (error) { + nandfs_error("%s: cannot destroy " + "block %jx, error %d\n", __func__, + (uintmax_t)ip->i_db[i], error); + return (error); + } + ip->i_db[i] = 0; + } + + left--; + } + + KASSERT(left == 0, + ("truncated wrong number of blocks (%jd should be 0)", left)); + + return (error); +} + +nandfs_lbn_t +get_maxfilesize(struct nandfs_device *fsdev) +{ + struct nandfs_indir f[NIADDR]; + nandfs_lbn_t max; + int i; + + max = NDADDR; + + for (i = 0; i < NIADDR; i++) { + f[i].in_off = MNINDIR(fsdev) - 1; + max += blocks_inside(fsdev, i, f); + } + + max *= fsdev->nd_blocksize; + + return (max); +} + +/* + * This is ufs_getlbns with minor modifications. + */ +/* + * Create an array of logical block number/offset pairs which represent the + * path of indirect blocks required to access a data block. The first "pair" + * contains the logical block number of the appropriate single, double or + * triple indirect block and the offset into the inode indirect block array. + * Note, the logical block number of the inode single/double/triple indirect + * block appears twice in the array, once with the offset into the i_ib and + * once with the offset into the page itself. + */ +static int +bmap_getlbns(struct nandfs_node *node, nandfs_lbn_t bn, struct nandfs_indir *ap, int *nump) +{ + nandfs_daddr_t blockcnt; + nandfs_lbn_t metalbn, realbn; + struct nandfs_device *fsdev; + int i, numlevels, off; + + fsdev = node->nn_nandfsdev; + + DPRINTF(BMAP, ("%s: node %p bn=%jx mnindir=%zd enter\n", __func__, + node, bn, MNINDIR(fsdev))); + + *nump = 0; + numlevels = 0; + realbn = bn; + + if (bn < 0) + bn = -bn; + + /* The first NDADDR blocks are direct blocks. */ + if (bn < NDADDR) + return (0); + + /* + * Determine the number of levels of indirection. After this loop + * is done, blockcnt indicates the number of data blocks possible + * at the previous level of indirection, and NIADDR - i is the number + * of levels of indirection needed to locate the requested block. + */ + for (blockcnt = 1, i = NIADDR, bn -= NDADDR;; i--, bn -= blockcnt) { + DPRINTF(BMAP, ("%s: blockcnt=%jd i=%d bn=%jd\n", __func__, + blockcnt, i, bn)); + if (i == 0) + return (EFBIG); + blockcnt *= MNINDIR(fsdev); + if (bn < blockcnt) + break; + } + + /* Calculate the address of the first meta-block. */ + if (realbn >= 0) + metalbn = -(realbn - bn + NIADDR - i); + else + metalbn = -(-realbn - bn + NIADDR - i); + + /* + * At each iteration, off is the offset into the bap array which is + * an array of disk addresses at the current level of indirection. + * The logical block number and the offset in that block are stored + * into the argument array. + */ + ap->in_lbn = metalbn; + ap->in_off = off = NIADDR - i; + + DPRINTF(BMAP, ("%s: initial: ap->in_lbn=%jx ap->in_off=%d\n", __func__, + metalbn, off)); + + ap++; + for (++numlevels; i <= NIADDR; i++) { + /* If searching for a meta-data block, quit when found. */ + if (metalbn == realbn) + break; + + blockcnt /= MNINDIR(fsdev); + off = (bn / blockcnt) % MNINDIR(fsdev); + + ++numlevels; + ap->in_lbn = metalbn; + ap->in_off = off; + + DPRINTF(BMAP, ("%s: in_lbn=%jx in_off=%d\n", __func__, + ap->in_lbn, ap->in_off)); + ++ap; + + metalbn -= -1 + off * blockcnt; + } + if (nump) + *nump = numlevels; + + DPRINTF(BMAP, ("%s: numlevels=%d\n", __func__, numlevels)); + + return (0); +} Added: projects/nand/sys/fs/nandfs/bmap.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ projects/nand/sys/fs/nandfs/bmap.h Sat Mar 17 02:39:20 2012 (r233068) @@ -0,0 +1,40 @@ +/*- + * Copyright (c) 2012 Semihalf + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _BMAP_H +#define _BMAP_H + +#include "nandfs_fs.h" + +int bmap_lookup(struct nandfs_node *, nandfs_lbn_t, nandfs_daddr_t *); +int bmap_insert_block(struct nandfs_node *, nandfs_lbn_t, nandfs_daddr_t); +int bmap_truncate_mapping(struct nandfs_node *, nandfs_lbn_t, nandfs_lbn_t); +int bmap_dirty_meta(struct nandfs_node *, nandfs_lbn_t, int); + +nandfs_lbn_t get_maxfilesize(struct nandfs_device *); + +#endif /* _BMAP_H */ Added: projects/nand/sys/fs/nandfs/nandfs.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ projects/nand/sys/fs/nandfs/nandfs.h Sat Mar 17 02:39:20 2012 (r233068) @@ -0,0 +1,283 @@ +/*- + * Copyright (c) 2010-2012 Semihalf + * Copyright (c) 2008, 2009 Reinoud Zandijk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * From: NetBSD: nilfs.h,v 1.1 2009/07/18 16:31:42 reinoud + * + * $FreeBSD$ + */ + +#ifndef _FS_NANDFS_NANDFS_H_ +#define _FS_NANDFS_NANDFS_H_ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include "nandfs_fs.h" + +MALLOC_DECLARE(M_NANDFSTEMP); + +/* Debug categories */ +#define NANDFS_DEBUG_VOLUMES 0x000001 +#define NANDFS_DEBUG_BLOCK 0x000004 +#define NANDFS_DEBUG_LOCKING 0x000008 +#define NANDFS_DEBUG_NODE 0x000010 +#define NANDFS_DEBUG_LOOKUP 0x000020 +#define NANDFS_DEBUG_READDIR 0x000040 +#define NANDFS_DEBUG_TRANSLATE 0x000080 +#define NANDFS_DEBUG_STRATEGY 0x000100 +#define NANDFS_DEBUG_READ 0x000200 +#define NANDFS_DEBUG_WRITE 0x000400 +#define NANDFS_DEBUG_IFILE 0x000800 +#define NANDFS_DEBUG_ATTR 0x001000 +#define NANDFS_DEBUG_EXTATTR 0x002000 +#define NANDFS_DEBUG_ALLOC 0x004000 +#define NANDFS_DEBUG_CPFILE 0x008000 +#define NANDFS_DEBUG_DIRHASH 0x010000 +#define NANDFS_DEBUG_NOTIMPL 0x020000 +#define NANDFS_DEBUG_SHEDULE 0x040000 +#define NANDFS_DEBUG_SEG 0x080000 +#define NANDFS_DEBUG_SYNC 0x100000 +#define NANDFS_DEBUG_PARANOIA 0x200000 +#define NANDFS_DEBUG_VNCALL 0x400000 +#define NANDFS_DEBUG_BUF 0x1000000 +#define NANDFS_DEBUG_BMAP 0x2000000 +#define NANDFS_DEBUG_DAT 0x4000000 +#define NANDFS_DEBUG_GENERIC 0x8000000 +#define NANDFS_DEBUG_CLEAN 0x10000000 + +extern int nandfs_verbose; + +#define DPRINTF(name, arg) { \ + if (nandfs_verbose & NANDFS_DEBUG_##name) {\ + printf arg;\ + };\ + } +#define DPRINTFIF(name, cond, arg) { \ + if (nandfs_verbose & NANDFS_DEBUG_##name) { \ + if (cond) printf arg;\ + };\ + } + +#define VFSTONANDFS(mp) ((struct nandfsmount *)((mp)->mnt_data)) +#define VTON(vp) ((struct nandfs_node *)(vp)->v_data) +#define NTOV(xp) ((xp)->nn_vnode) + +int nandfs_init(struct vfsconf *); +int nandfs_uninit(struct vfsconf *); + +extern struct vop_vector nandfs_vnodeops; + +struct nandfs_node; + +/* Structure and derivatives */ +struct nandfs_mdt { + uint32_t entries_per_block; + uint32_t entries_per_group; + uint32_t blocks_per_group; + uint32_t groups_per_desc_block; /* desc is super group */ + uint32_t blocks_per_desc_block; /* desc is super group */ +}; + +struct nandfs_segment { + LIST_ENTRY(nandfs_segment) seg_link; + + struct nandfs_device *fsdev; + + TAILQ_HEAD(, buf) segsum; + TAILQ_HEAD(, buf) data; + + uint64_t seg_num; + uint64_t seg_next; + uint64_t start_block; + uint32_t num_blocks; + + uint32_t nfinfos; + uint32_t nblocks; + uint32_t segsum_blocks; + uint32_t segsum_bytes; + uint32_t bytes_left; + char *current_off; +}; + +struct nandfs_seginfo { + LIST_HEAD( ,nandfs_segment) seg_list; + struct nandfs_segment *curseg; + struct nandfs_device *fsdev; + uint32_t blocks; + uint32_t finfos; + uint8_t reiterate; +}; + +#define NANDFS_FSSTOR_FAILED 1 +struct nandfs_fsarea { + int offset; + int flags; + int last_used; +}; + +struct nandfs_device { + struct vnode *nd_devvp; + struct g_consumer *nd_gconsumer; + + int nd_is_nand; + + struct nandfs_fsarea nd_fsarea[NANDFS_NFSAREAS]; + int nd_last_fsarea; + + STAILQ_HEAD(nandfs_mnts, nandfsmount) nd_mounts; + SLIST_ENTRY(nandfs_device) nd_next_device; + + /* FS structures */ + struct nandfs_fsdata nd_fsdata; + struct nandfs_super_block nd_super; + struct nandfs_segment_summary nd_last_segsum; + struct nandfs_super_root nd_super_root; + struct nandfs_node *nd_dat_node; + struct nandfs_node *nd_cp_node; + struct nandfs_node *nd_su_node; + struct nandfs_node *nd_gc_node; + + struct nandfs_mdt nd_dat_mdt; + struct nandfs_mdt nd_ifile_mdt; + + struct timespec nd_ts; + + /* Synchronization */ + struct mtx nd_mutex; + struct mtx nd_sync_mtx; + struct cv nd_sync_cv; + struct lock nd_seg_const; + + struct nandfs_seginfo *nd_seginfo; + + int32_t nd_cleanerd_pid; + + /* FS geometry */ + uint64_t nd_devsize; + uint64_t nd_maxfilesize; + uint32_t nd_blocksize; + uint32_t nd_erasesize; + + uint32_t nd_devblocksize; + + /* Segment usage */ + uint64_t nd_clean_segs; + uint64_t *nd_free_base; + uint64_t nd_free_count; + uint64_t nd_dirty_bufs; + + /* Running values */ + uint64_t nd_seg_sequence; + uint64_t nd_seg_num; + uint64_t nd_next_seg_num; + uint64_t nd_last_pseg; + uint64_t nd_last_cno; + uint64_t nd_last_ino; + uint64_t nd_fakevblk; + + int nd_mount_state; + int nd_refcnt; + int nd_syncing; +}; + +extern SLIST_HEAD(_nandfs_devices, nandfs_device) nandfs_devices; + +#define NANDFS_KILL_SYNCER 0x1 +#define NANDFS_FORCE_SYNCER 0x2 +#define NANDFS_NOLOCK_SYNCER 0x4 +#define NANDFS_UMOUNT 0x8 + +#define SYNCER_UMOUNT 0x0 +#define SYNCER_VFS_SYNC 0x1 +#define SYNCER_BDFLUSH 0x2 +#define SYNCER_FFORCE 0x3 +#define SYNCER_FSYNC 0x4 +#define SYNCER_ROUPD 0x5 + +/* Specific mountpoint; head or a checkpoint/snapshot */ +struct nandfsmount { + STAILQ_ENTRY(nandfsmount) nm_next_mount; + + struct mount *nm_vfs_mountp; + struct nandfs_device *nm_nandfsdev; + struct nandfs_args nm_mount_args; + struct nandfs_node *nm_ifile_node; + struct proc *nm_syncer; + struct sysctl_oid *nm_mountpoint_oid; + + uint8_t nm_flags; + int8_t nm_ronly; +}; + +struct nandfs_indirect{ + TAILQ_ENTRY(nandfs_indirect) list_entry; + struct nandfs_indir indices; + struct buf *bp; +}; + +struct nandfs_node { + struct vnode *nn_vnode; + struct nandfsmount *nn_nmp; + struct nandfs_device *nn_nandfsdev; + struct lockf *nn_lockf; + + uint64_t nn_ino; + struct nandfs_inode nn_inode; + + uint64_t nn_diroff; + uint32_t nn_flags; +}; + +#define IN_ACCESS 0x0001 /* Inode access time update request */ +#define IN_CHANGE 0x0002 /* Inode change time update request */ +#define IN_UPDATE 0x0004 /* Inode was written to; update mtime*/ +#define IN_MODIFIED 0x0008 /* node has been modified */ +#define IN_RENAME 0x0010 /* node is being renamed. */ + +/* File permissions. */ +#define IEXEC 0000100 /* Executable. */ +#define IWRITE 0000200 /* Writeable. */ +#define IREAD 0000400 /* Readable. */ +#define ISVTX 0001000 /* Sticky bit. */ +#define ISGID 0002000 /* Set-gid. */ +#define ISUID 0004000 /* Set-uid. */ + +#define PRINT_NODE_FLAGS \ + "\10\1IN_ACCESS\2IN_CHANGE\3IN_UPDATE\4IN_MODIFIED\5IN_RENAME" + +#define NANDFS_GATHER(x) ((x)->b_flags |= B_00800000) +#define NANDFS_UNGATHER(x) ((x)->b_flags &= ~B_00800000) +#define NANDFS_ISGATHERED(x) ((x)->b_flags & B_00800000) + +#endif /* !_FS_NANDFS_NANDFS_H_ */ Added: projects/nand/sys/fs/nandfs/nandfs_alloc.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ projects/nand/sys/fs/nandfs/nandfs_alloc.c Sat Mar 17 02:39:20 2012 (r233068) @@ -0,0 +1,363 @@ +/*- + * Copyright (c) 2010-2012 Semihalf. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***