6f7c735300
The NAND Flash environment consists of several distinct components: - NAND framework (drivers harness for NAND controllers and NAND chips) - NAND simulator (NANDsim) - NAND file system (NAND FS) - Companion tools and utilities - Documentation (manual pages) This work is still experimental. Please use with caution. Obtained from: Semihalf Supported by: FreeBSD Foundation, Juniper Networks
231 lines
5.5 KiB
C
231 lines
5.5 KiB
C
/*-
|
|
* 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_subr.c,v 1.4 2009/07/29 17:06:57 reinoud
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/namei.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/buf.h>
|
|
#include <sys/bio.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/mount.h>
|
|
#include <sys/vnode.h>
|
|
#include <sys/signalvar.h>
|
|
#include <sys/malloc.h>
|
|
#include <sys/dirent.h>
|
|
#include <sys/lockf.h>
|
|
#include <sys/ktr.h>
|
|
|
|
#include <vm/vm.h>
|
|
#include <vm/vm_extern.h>
|
|
#include <vm/vm_object.h>
|
|
#include <vm/vnode_pager.h>
|
|
|
|
#include <machine/_inttypes.h>
|
|
|
|
#include <vm/vm.h>
|
|
#include <vm/vm_extern.h>
|
|
#include <vm/vm_object.h>
|
|
#include <vm/vnode_pager.h>
|
|
|
|
#include "nandfs_mount.h"
|
|
#include "nandfs.h"
|
|
#include "nandfs_subr.h"
|
|
#include "bmap.h"
|
|
|
|
nandfs_lbn_t
|
|
nandfs_get_maxfilesize(struct nandfs_device *fsdev)
|
|
{
|
|
|
|
return (get_maxfilesize(fsdev));
|
|
}
|
|
|
|
int
|
|
nandfs_bmap_lookup(struct nandfs_node *node, nandfs_lbn_t lblk,
|
|
nandfs_daddr_t *vblk)
|
|
{
|
|
int error = 0;
|
|
|
|
if (node->nn_ino == NANDFS_GC_INO && lblk >= 0)
|
|
*vblk = lblk;
|
|
else
|
|
error = bmap_lookup(node, lblk, vblk);
|
|
|
|
DPRINTF(TRANSLATE, ("%s: error %d ino %#jx lblocknr %#jx -> %#jx\n",
|
|
__func__, error, (uintmax_t)node->nn_ino, (uintmax_t)lblk,
|
|
(uintmax_t)*vblk));
|
|
|
|
if (error)
|
|
nandfs_error("%s: returned %d", __func__, error);
|
|
|
|
return (error);
|
|
}
|
|
|
|
int
|
|
nandfs_bmap_insert_block(struct nandfs_node *node, nandfs_lbn_t lblk,
|
|
struct buf *bp)
|
|
{
|
|
struct nandfs_device *fsdev;
|
|
nandfs_daddr_t vblk;
|
|
int error;
|
|
|
|
fsdev = node->nn_nandfsdev;
|
|
|
|
vblk = 0;
|
|
if (node->nn_ino != NANDFS_DAT_INO) {
|
|
error = nandfs_vblock_alloc(fsdev, &vblk);
|
|
if (error)
|
|
return (error);
|
|
}
|
|
|
|
nandfs_buf_set(bp, NANDFS_VBLK_ASSIGNED);
|
|
nandfs_vblk_set(bp, vblk);
|
|
|
|
error = bmap_insert_block(node, lblk, vblk);
|
|
if (error) {
|
|
nandfs_vblock_free(fsdev, vblk);
|
|
return (error);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
nandfs_bmap_dirty_blocks(struct nandfs_node *node, struct buf *bp, int force)
|
|
{
|
|
int error;
|
|
|
|
error = bmap_dirty_meta(node, bp->b_lblkno, force);
|
|
if (error)
|
|
nandfs_error("%s: cannot dirty buffer %p\n",
|
|
__func__, bp);
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
nandfs_bmap_update_mapping(struct nandfs_node *node, nandfs_lbn_t lblk,
|
|
nandfs_daddr_t blknr)
|
|
{
|
|
int error;
|
|
|
|
DPRINTF(BMAP,
|
|
("%s: node: %p ino: %#jx lblk: %#jx vblk: %#jx\n",
|
|
__func__, node, (uintmax_t)node->nn_ino, (uintmax_t)lblk,
|
|
(uintmax_t)blknr));
|
|
|
|
error = bmap_insert_block(node, lblk, blknr);
|
|
|
|
return (error);
|
|
}
|
|
|
|
int
|
|
nandfs_bmap_update_block(struct nandfs_node *node, struct buf *bp,
|
|
nandfs_lbn_t blknr)
|
|
{
|
|
nandfs_lbn_t lblk;
|
|
int error;
|
|
|
|
lblk = bp->b_lblkno;
|
|
nandfs_vblk_set(bp, blknr);
|
|
|
|
DPRINTF(BMAP, ("%s: node: %p ino: %#jx bp: %p lblk: %#jx blk: %#jx\n",
|
|
__func__, node, (uintmax_t)node->nn_ino, bp,
|
|
(uintmax_t)lblk, (uintmax_t)blknr));
|
|
|
|
error = nandfs_bmap_update_mapping(node, lblk, blknr);
|
|
if (error) {
|
|
nandfs_error("%s: cannot update lblk:%jx to blk:%jx for "
|
|
"node:%p, error:%d\n", __func__, (uintmax_t)lblk,
|
|
(uintmax_t)blknr, node, error);
|
|
return (error);
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
int
|
|
nandfs_bmap_update_dat(struct nandfs_node *node, nandfs_daddr_t oldblk,
|
|
struct buf *bp)
|
|
{
|
|
struct nandfs_device *fsdev;
|
|
nandfs_daddr_t vblk = 0;
|
|
int error;
|
|
|
|
if (node->nn_ino == NANDFS_DAT_INO)
|
|
return (0);
|
|
|
|
if (nandfs_buf_check(bp, NANDFS_VBLK_ASSIGNED)) {
|
|
nandfs_buf_clear(bp, NANDFS_VBLK_ASSIGNED);
|
|
return (0);
|
|
}
|
|
|
|
fsdev = node->nn_nandfsdev;
|
|
|
|
/* First alloc new virtual block.... */
|
|
error = nandfs_vblock_alloc(fsdev, &vblk);
|
|
if (error)
|
|
return (error);
|
|
|
|
error = nandfs_bmap_update_block(node, bp, vblk);
|
|
if (error)
|
|
return (error);
|
|
|
|
/* Then we can end up with old one */
|
|
nandfs_vblock_end(fsdev, oldblk);
|
|
|
|
DPRINTF(BMAP,
|
|
("%s: ino %#jx block %#jx: update vblk %#jx to %#jx\n",
|
|
__func__, (uintmax_t)node->nn_ino, (uintmax_t)bp->b_lblkno,
|
|
(uintmax_t)oldblk, (uintmax_t)vblk));
|
|
return (error);
|
|
}
|
|
|
|
int
|
|
nandfs_bmap_truncate_mapping(struct nandfs_node *node, nandfs_lbn_t oblk,
|
|
nandfs_lbn_t nblk)
|
|
{
|
|
nandfs_lbn_t todo;
|
|
int error;
|
|
|
|
todo = oblk - nblk;
|
|
|
|
DPRINTF(BMAP, ("%s: node %p oblk %jx nblk %jx truncate by %jx\n",
|
|
__func__, node, oblk, nblk, todo));
|
|
|
|
error = bmap_truncate_mapping(node, oblk, todo);
|
|
if (error)
|
|
return (error);
|
|
|
|
return (error);
|
|
}
|