Import CHFS, which was formerly known as ChewieFS.

CHFS is a file system for flash devices developed by the
Software Engineering Department at University of Szeged, Hungary.

http://chewiefs.sed.hu/

Thanks for all who made it possible.
This commit is contained in:
ahoka 2011-11-24 15:51:30 +00:00
parent 277dab7940
commit 288addd0db
30 changed files with 13788 additions and 25 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: vnode.h,v 1.235 2011/11/21 04:36:06 christos Exp $ */
/* $NetBSD: vnode.h,v 1.236 2011/11/24 15:51:30 ahoka Exp $ */
/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc.
@ -105,7 +105,7 @@ enum vtagtype {
VT_AFS, VT_ISOFS, VT_UNION, VT_ADOSFS, VT_EXT2FS, VT_CODA,
VT_FILECORE, VT_NTFS, VT_VFS, VT_OVERLAY, VT_SMBFS, VT_PTYFS,
VT_TMPFS, VT_UDF, VT_SYSVBFS, VT_PUFFS, VT_HFS, VT_EFS, VT_ZFS,
VT_RUMP, VT_NILFS, VT_V7FS
VT_RUMP, VT_NILFS, VT_V7FS, VT_CHFS
};
#define VNODE_TAGS \
@ -114,7 +114,7 @@ enum vtagtype {
"VT_AFS", "VT_ISOFS", "VT_UNION", "VT_ADOSFS", "VT_EXT2FS", "VT_CODA", \
"VT_FILECORE", "VT_NTFS", "VT_VFS", "VT_OVERLAY", "VT_SMBFS", "VT_PTYFS", \
"VT_TMPFS", "VT_UDF", "VT_SYSVBFS", "VT_PUFFS", "VT_HFS", "VT_EFS", \
"VT_ZFS", "VT_RUMP", "VT_NILFS", "VT_V7FS"
"VT_ZFS", "VT_RUMP", "VT_NILFS", "VT_V7FS", "VT_CHFS"
struct vnode;
struct buf;
@ -223,7 +223,7 @@ typedef struct vnode vnode_t;
"\20\1ROOT\2SYSTEM\3ISTTY\4MAPPED\5MPSAFE\6LOCKSWORK\11TEXT\12EXECMAP" \
"\13WRMAP\14WRMAPDIRTY\15XLOCK\17ONWORKLST\20MARKER" \
"\22LAYER\24CLEAN\25INACTPEND\26INACTREDO" \
"\30INACTNOW\31DIROP"
"\30INACTNOW\31DIROP"
#define VSIZENOTSET ((voff_t)-1)

910
sys/ufs/chfs/chfs.h Normal file
View File

@ -0,0 +1,910 @@
/* $NetBSD: chfs.h,v 1.1 2011/11/24 15:51:31 ahoka Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
* University of Szeged, Hungary
* Copyright (C) 2009 Ferenc Havasi <havasi@inf.u-szeged.hu>
* Copyright (C) 2009 Zoltan Sogor <weth@inf.u-szeged.hu>
* Copyright (C) 2009 David Tengeri <dtengeri@inf.u-szeged.hu>
* Copyright (C) 2009 Tamas Toth <ttoth@inf.u-szeged.hu>
* Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* 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.
*/
#ifndef __CHFS_H__
#define __CHFS_H__
#define DBG_MSG
#define DBG_MSG_GC
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/cdefs.h>
#include <sys/stdint.h>
#include <sys/types.h>
#include <sys/tree.h>
#include <sys/queue.h>
#include <sys/kmem.h>
#include <sys/endian.h>
#include <sys/rwlock.h>
#include <sys/condvar.h>
#include <sys/mutex.h>
#include <sys/kthread.h>
#include <sys/rbtree.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/hash.h>
#include <sys/module.h>
#include <sys/dirent.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/dir.h>
/* XXX shouldnt be defined here, but needed by chfs_inode.h */
TAILQ_HEAD(chfs_dirent_list, chfs_dirent);
#include "chfs_pool.h"
#include "ebh.h"
#include "media.h"
#include "chfs_inode.h"
#ifndef MOUNT_CHFS
#define MOUNT_CHFS "chfs"
#endif
#define CHFS_ROOTINO ROOTINO /* ROOTINO == 2 */
enum {
VNO_STATE_UNCHECKED, /* CRC checks not yet done */
VNO_STATE_CHECKING, /* CRC checks in progress */
VNO_STATE_PRESENT, /* In core */
VNO_STATE_CHECKEDABSENT,/* Checked, cleared again */
VNO_STATE_GC, /* GCing a 'pristine' node */
VNO_STATE_READING, /* In read_inode() */
VNO_STATE_CLEARING /* In clear_inode() */
};
#define VNODECACHE_SIZE 128
#define MAX_READ_FREE(chmp) (((chmp)->chm_ebh)->eb_size / 8)
/* an eraseblock will be clean if its dirty size is smaller than this */
#define MAX_DIRTY_TO_CLEAN 255
#define VERY_DIRTY(chmp, size) ((size) >= (((chmp)->chm_ebh)->eb_size / 2))
#define CHFS_PAD(x) (((x)+3)&~3)
enum {
CHFS_NODE_OK = 0,
CHFS_NODE_BADMAGIC,
CHFS_NODE_BADCRC,
CHFS_NODE_BADNAMECRC
};
enum {
CHFS_BLK_STATE_FREE = 100,
CHFS_BLK_STATE_CLEAN,
CHFS_BLK_STATE_PARTDIRTY,
CHFS_BLK_STATE_ALLDIRTY
};
extern struct pool chfs_inode_pool;
extern const struct genfs_ops chfs_genfsops;
/**
* struct chfs_node_ref - a reference to a node
* @lnr: logical identifier of the eraseblock where the node is
* @offset: offset int hte eraseblock where the node starts
* @next: used at data and dirent nodes, it points to the next data node which
* belongs to the same vnode
*/
struct chfs_node_ref
{
struct chfs_node_ref *nref_next;
uint32_t nref_lnr;
uint32_t nref_offset;
};
/* Constants for allocating node refs */
#define REFS_BLOCK_LEN (255/sizeof(struct chfs_node_ref))
#define REF_EMPTY_NODE (UINT_MAX)
#define REF_LINK_TO_NEXT (UINT_MAX - 1)
enum {
CHFS_NORMAL_NODE_MASK,
CHFS_UNCHECKED_NODE_MASK,
CHFS_OBSOLETE_NODE_MASK,
CHFS_PRISTINE_NODE_MASK
};
#define CHFS_REF_FLAGS(ref) ((ref)->nref_offset & 3)
#define CHFS_REF_OBSOLETE(ref) (((ref)->nref_offset & 3) == CHFS_OBSOLETE_NODE_MASK)
#define CHFS_MARK_REF_NORMAL(ref) \
do { \
(ref)->nref_offset = CHFS_GET_OFS((ref)->nref_offset) | CHFS_NORMAL_NODE_MASK; \
} while(0)
#define CHFS_GET_OFS(ofs) (ofs & ~ 3)
static inline struct chfs_node_ref *
node_next(struct chfs_node_ref *nref)
{
//dbg("node next: %u : %u\n", nref->nref_lnr, nref->nref_offset);
nref++;
//dbg("nref++: %u : %u\n", nref->nref_lnr, nref->nref_offset);
if (nref->nref_lnr == REF_LINK_TO_NEXT) {
//dbg("link to next\n");
nref = nref->nref_next;
if (!nref)
return nref;
}
if (nref->nref_lnr == REF_EMPTY_NODE) {
//dbg("empty\n");
return NULL;
}
return nref;
}
/**
* struct chfs_dirent - full representation of a directory entry
*/
struct chfs_dirent
{
struct chfs_node_ref *nref;
// struct chfs_dirent *next;
TAILQ_ENTRY(chfs_dirent) fds;
uint64_t version;
ino_t vno;
uint32_t nhash;
enum vtype type;
uint8_t nsize;
uint8_t name[0];
/* used by chfs_alloc_dirent and free counterpart */
// size_t alloc_size;
};
struct chfs_tmp_dnode {
struct chfs_full_dnode *node;
uint64_t version;
uint32_t data_crc;
//uint32_t partial_crc;
//uint16_t csize;
uint16_t overlapped;
struct chfs_tmp_dnode *next;
};
struct chfs_tmp_dnode_info {
struct rb_node rb_node;
struct chfs_tmp_dnode *tmpnode;
};
struct chfs_readinode_info {
struct rb_tree tdi_root;
struct chfs_tmp_dnode_info *mdata_tn;
uint64_t highest_version;
struct chfs_node_ref *latest_ref;
};
struct chfs_full_dnode {
struct chfs_node_ref *nref;
uint64_t ofs;
uint32_t size;
uint32_t frags;
};
struct chfs_node_frag {
struct rb_node rb_node;
struct chfs_full_dnode *node;
uint32_t size;
uint64_t ofs;
};
static inline struct chfs_node_frag *
frag_first(struct rb_tree *tree)
{
struct chfs_node_frag *frag;
frag = (struct chfs_node_frag *)RB_TREE_MIN(tree);
return frag;
}
static inline struct chfs_node_frag *
frag_last(struct rb_tree *tree)
{
struct chfs_node_frag *frag;
frag = (struct chfs_node_frag *)RB_TREE_MAX(tree);
return frag;
}
#define frag_next(tree, frag) (struct chfs_node_frag *)rb_tree_iterate(tree, frag, RB_DIR_RIGHT)
#define frag_prev(tree, frag) (struct chfs_node_frag *)rb_tree_iterate(tree, frag, RB_DIR_LEFT)
/* XXX hack
#ifndef CHFS_FRAG_TREE
#define CHFS_FRAG_TREE
RB_HEAD(chfs_frag_tree, chfs_node_frag);
#endif
*/
/* for prototypes, properly defined in chfs_inode.h */
//struct chfs_inode_ext;
/**
* struct chfs_vnode_cache - in memory representation of a vnode
* @v: pointer to the vnode info node
* @dnode: pointer to the list of data nodes
* @dirents: pointer to the list of directory entries
* @vno_version: used only during scan, holds the current version number of
* chfs_flash_vnode
* @scan_dirents: used only during scan, holds the full representation of
* directory entries of this vnode
* @pvno: parent vnode number
* @nlink: number of links to this vnode
*/
struct chfs_vnode_cache {
// struct chfs_dirent *scan_dirents;
void *p;
struct chfs_dirent_list scan_dirents;
struct chfs_node_ref *v;
struct chfs_node_ref *dnode;
struct chfs_node_ref *dirents;
uint64_t *vno_version;
uint64_t highest_version;
uint8_t flags;
uint16_t state;
ino_t vno;
ino_t pvno;
struct chfs_vnode_cache* next;
uint32_t nlink;
};
struct chfs_eraseblock
{
uint32_t lnr;
TAILQ_ENTRY(chfs_eraseblock) queue;
//uint32_t bad_count;
uint32_t unchecked_size;
uint32_t used_size;
uint32_t dirty_size;
uint32_t free_size;
uint32_t wasted_size;
struct chfs_node_ref *first_node;
struct chfs_node_ref *last_node;
struct chfs_node_ref *gc_node; /* Next block to be garbage collected */
};
TAILQ_HEAD(chfs_eraseblock_queue, chfs_eraseblock);
#define ALLOC_NORMAL 0
#define ALLOC_DELETION 1
#define ALLOC_GC 2
struct garbage_collector_thread {
lwp_t *gcth_thread;
kcondvar_t gcth_wakeup;
bool gcth_running;
};
#define CHFS_MP_FLAG_SCANNING 2
#define CHFS_MP_FLAG_BUILDING 4
/**
* struct chfs_mount - CHFS main descriptor structure
* @ebh: eraseblock handler
* @fl_index: index of flash device in the flash layer
* @fs_version: filesystem version descriptor
* @gbl_version: global version number
* @max_vno: max vnode id
* @chm_lock_mountfields:
* @vnocache_hash: hash table of vnode caches
* @vnocache_lock:
* @blocks: array of eraseblocks on flash
* @chm_root: used to protect all fields
* @free_size: free size on the flash
* @dirty_size: dirtied size on flash
* @unchecked_size: size of unchecked data on flash
* @free_queue: queue of free eraseblocks
* @clean_queue: queue of clean eraseblocks
* @dirty_queue: queue of dirty eraseblocks
* @very_dirty_queue: queue of very dirty eraseblocks
* @erase_pending_queue: queue of eraseblocks waiting for erasing
* @erasable_pending_wbuf_queue: queue of eraseblocks waiting for erasing and
* have data to write to them
* @nextblock: next eraseblock to write to
*
* @nr_free_blocks: number of free blocks on the free_queue
* @nr_erasable_blocks: number of blocks that can be erased and are on the
* erasable_queue
*
*/
struct chfs_mount {
struct mount *chm_fsmp;
// dev_t dev;
// struct vnode *devvp;
struct chfs_ebh *chm_ebh;
// int chm_fl_index;
int chm_fs_version;
uint64_t chm_gbl_version;
ino_t chm_max_vno;
ino_t chm_checked_vno;
unsigned int chm_flags;
/* chm_lock_mountfields:
* Used to protect all the following fields. */
kmutex_t chm_lock_mountfields;
struct chfs_vnode_cache **chm_vnocache_hash;
/* chm_lock_vnocache:
* Used to protect the vnode cache.
* If you have to lock chm_lock_mountfields and also chm_lock_vnocache,
* you must lock chm_lock_mountfields first. */
kmutex_t chm_lock_vnocache;
struct chfs_eraseblock *chm_blocks;
struct chfs_node *chm_root;
uint32_t chm_free_size;
uint32_t chm_dirty_size;
uint32_t chm_unchecked_size;
uint32_t chm_used_size;
uint32_t chm_wasted_size;
/* chm_lock_sizes:
* Used to protect the (free, used, etc.) sizes of the FS
* (and also the sizes of each eraseblock).
* If you have to lock chm_lock_mountfields and also chm_lock_sizes,
* you must lock chm_lock_mountfields first. */
kmutex_t chm_lock_sizes;
struct chfs_eraseblock_queue chm_free_queue;
struct chfs_eraseblock_queue chm_clean_queue;
struct chfs_eraseblock_queue chm_dirty_queue;
struct chfs_eraseblock_queue chm_very_dirty_queue;
struct chfs_eraseblock_queue chm_erasable_pending_wbuf_queue;
struct chfs_eraseblock_queue chm_erase_pending_queue;
uint8_t chm_resv_blocks_deletion;
uint8_t chm_resv_blocks_write;
uint8_t chm_resv_blocks_gctrigger;
uint8_t chm_resv_blocks_gcmerge;
uint8_t chm_nospc_dirty;
uint8_t chm_vdirty_blocks_gctrigger;
struct chfs_eraseblock *chm_nextblock;
struct garbage_collector_thread chm_gc_thread;
struct chfs_eraseblock *chm_gcblock;
int chm_nr_free_blocks;
int chm_nr_erasable_blocks;
int32_t chm_fs_bmask;
int32_t chm_fs_bsize;
int32_t chm_fs_qbmask;
int32_t chm_fs_bshift;
int32_t chm_fs_fmask;
int64_t chm_fs_qfmask;
/* TODO will we use these? */
unsigned int chm_pages_max;
unsigned int chm_pages_used;
unsigned int chm_nodes_max;
unsigned int chm_nodes_cnt;
struct chfs_pool chm_dirent_pool;
struct chfs_pool chm_node_pool;
struct chfs_str_pool chm_str_pool;
/**/
size_t chm_wbuf_pagesize;
unsigned char* chm_wbuf;
size_t chm_wbuf_ofs;
size_t chm_wbuf_len;
/* chm_lock_wbuf:
* Used to protect the write buffer.
* If you have to lock chm_lock_mountfields and also chm_lock_wbuf,
* you must lock chm_lock_mountfields first. */
krwlock_t chm_lock_wbuf;
};
#define sleep_on_spinunlock(s) \
do { \
kmutex_t sleep_mtx; \
kcondvar_t sleep_cnd; \
cv_init(&sleep_cnd, "sleep_cnd"); \
mutex_init(&sleep_mtx, MUTEX_DEFAULT, IPL_NONE); \
mutex_spin_exit(s); \
mutex_enter(&sleep_mtx); \
cv_timedwait(&sleep_cnd, &sleep_mtx, mstohz(50)); \
mutex_exit(&sleep_mtx); \
mutex_destroy(&sleep_mtx); \
cv_destroy(&sleep_cnd); \
} while (0)
#undef sleep_on_spinunlock
/*
* TODO we should move here all of these from the bottom of the file
* Macros/functions to convert from generic data structures to chfs
* specific ones.
*/
#define CHFS_OFFSET_DOT 0
#define CHFS_OFFSET_DOTDOT 1
#define CHFS_OFFSET_EOF 2
#define CHFS_OFFSET_FIRST 3
/*---------------------------------------------------------------------------*/
/* chfs_build.c */
void chfs_calc_trigger_levels(struct chfs_mount *);
int chfs_build_filesystem(struct chfs_mount *);
void chfs_build_set_vnodecache_nlink(struct chfs_mount *chmp,struct chfs_vnode_cache *vc);
void chfs_build_remove_unlinked_vnode(struct chfs_mount *chmp,struct chfs_vnode_cache *vc, struct chfs_dirent_list *unlinked);
/* chfs_scan.c */
int chfs_scan_eraseblock(struct chfs_mount *, struct chfs_eraseblock *);
struct chfs_vnode_cache *chfs_scan_make_vnode_cache(struct chfs_mount *chmp, ino_t vno);
int chfs_scan_check_node_hdr(struct chfs_flash_node_hdr *nhdr);
int chfs_scan_check_vnode(struct chfs_mount *chmp, struct chfs_eraseblock *cheb, void *buf, off_t ofs);
int chfs_scan_mark_dirent_obsolete(struct chfs_mount *chmp,struct chfs_vnode_cache *vc, struct chfs_dirent *fd);
void chfs_add_fd_to_list(struct chfs_mount *chmp,struct chfs_dirent *new, struct chfs_vnode_cache *pvc);
int chfs_scan_check_dirent_node(struct chfs_mount *chmp, struct chfs_eraseblock *cheb, void *buf, off_t ofs);
int chfs_scan_check_data_node(struct chfs_mount *chmp, struct chfs_eraseblock *cheb, void *buf, off_t ofs);
int chfs_scan_classify_cheb(struct chfs_mount *chmp,struct chfs_eraseblock *cheb);
/* chfs_nodeops.c */
int chfs_update_eb_dirty(struct chfs_mount *, struct chfs_eraseblock *, uint32_t);
void chfs_add_node_to_list(struct chfs_mount *, struct chfs_vnode_cache *,
struct chfs_node_ref *, struct chfs_node_ref **);
void chfs_add_fd_to_inode(struct chfs_mount *,
struct chfs_inode *, struct chfs_dirent *);
void chfs_add_vnode_ref_to_vc(struct chfs_mount *, struct chfs_vnode_cache *,
struct chfs_node_ref *);
struct chfs_node_ref* chfs_nref_next(struct chfs_node_ref *);
int chfs_nref_len(struct chfs_mount *,
struct chfs_eraseblock *, struct chfs_node_ref *);
int chfs_close_eraseblock(struct chfs_mount *,
struct chfs_eraseblock *);
int chfs_reserve_space_normal(struct chfs_mount *, uint32_t, int);
int chfs_reserve_space_gc(struct chfs_mount *, uint32_t);
int chfs_reserve_space(struct chfs_mount *, uint32_t);
void chfs_mark_node_obsolete(struct chfs_mount *, struct chfs_node_ref *);
static inline struct chfs_vnode_cache *
chfs_nref_to_vc(struct chfs_node_ref *nref)
{
while (nref->nref_next) {
nref = nref->nref_next;
//dbg("lnr: %u, ofs: %u\n", nref->nref_lnr, nref->nref_offset);
//dbg("vno: %llu\n", ((struct chfs_vnode_cache *)(nref))->vno);
//dbg("scan_dirents: %p\n", ((struct chfs_vnode_cache *)(nref))->scan_dirents);
if (nref->nref_lnr == REF_LINK_TO_NEXT) {
dbg("Link to next!\n");
} else if (nref->nref_lnr == REF_EMPTY_NODE) {
dbg("Empty!\n");
}
}
//dbg("vno: %llu\n", ((struct chfs_vnode_cache *)(nref))->vno);
//dbg("NREF_TO_VC: GET IT\n");
//dbg("nref_next: %p, lnr: %u, ofs: %u\n", nref->nref_next, nref->nref_lnr, nref->nref_offset);
struct chfs_vnode_cache *vc = (struct chfs_vnode_cache *) nref;
dbg("vno: %llu, pvno: %llu, hv: %llu, nlink: %u\n", vc->vno, vc->pvno, vc->highest_version, vc->nlink);
//return ((struct chfs_vnode_cache *)nref);
return vc;
}
/* chfs_malloc.c */
int chfs_alloc_pool_caches(void);
void chfs_destroy_pool_caches(void);
struct chfs_vnode_cache* chfs_vnode_cache_alloc(ino_t);
void chfs_vnode_cache_free(struct chfs_vnode_cache *);
struct chfs_node_ref* chfs_alloc_node_ref(
struct chfs_eraseblock *);
void chfs_free_node_refs(struct chfs_eraseblock *cheb);
struct chfs_dirent* chfs_alloc_dirent(int);
void chfs_free_dirent(struct chfs_dirent *);
struct chfs_flash_vnode* chfs_alloc_flash_vnode(void);
void chfs_free_flash_vnode(struct chfs_flash_vnode *);
struct chfs_flash_dirent_node* chfs_alloc_flash_dirent(void);
void chfs_free_flash_dirent(struct chfs_flash_dirent_node *);
struct chfs_flash_data_node* chfs_alloc_flash_dnode(void);
void chfs_free_flash_dnode(struct chfs_flash_data_node *);
struct chfs_node_frag* chfs_alloc_node_frag(void);
void chfs_free_node_frag(struct chfs_node_frag *);
struct chfs_node_ref* chfs_alloc_refblock(void);
void chfs_free_refblock(struct chfs_node_ref *nref);
struct chfs_full_dnode* chfs_alloc_full_dnode(void);
void chfs_free_full_dnode(struct chfs_full_dnode *fd);
struct chfs_tmp_dnode * chfs_alloc_tmp_dnode(void);
void chfs_free_tmp_dnode(struct chfs_tmp_dnode *);
struct chfs_tmp_dnode_info * chfs_alloc_tmp_dnode_info(void);
void chfs_free_tmp_dnode_info(struct chfs_tmp_dnode_info *);
/* chfs_readinode.c */
int chfs_read_inode(struct chfs_mount *, struct chfs_inode *);
int chfs_read_inode_internal(struct chfs_mount *, struct chfs_inode *);
void chfs_kill_fragtree(struct rb_tree *);
uint32_t chfs_truncate_fragtree(struct chfs_mount *,
struct rb_tree *, uint32_t);
int chfs_add_full_dnode_to_inode(struct chfs_mount *,
struct chfs_inode *,
struct chfs_full_dnode *);
int chfs_read_data(struct chfs_mount*, struct vnode *,
struct buf *);
/* chfs_erase.c */
int chfs_remap_leb(struct chfs_mount *chmp);
/* chfs_ihash.c */
void chfs_ihashinit(void);
void chfs_ihashreinit(void);
void chfs_ihashdone(void);
struct vnode *chfs_ihashlookup(dev_t, ino_t);
struct vnode *chfs_ihashget(dev_t, ino_t, int);
void chfs_ihashins(struct chfs_inode *);
void chfs_ihashrem(struct chfs_inode *);
extern kmutex_t chfs_ihash_lock;
extern kmutex_t chfs_hashlock;
/* chfs_gc.c */
void chfs_gc_trigger(struct chfs_mount *);
int chfs_gc_thread_should_wake(struct chfs_mount *);
void chfs_gc_thread(void *);
void chfs_gc_thread_start(struct chfs_mount *);
void chfs_gc_thread_stop(struct chfs_mount *);
int chfs_gcollect_pass(struct chfs_mount *);
/* chfs_vfsops.c*/
int chfs_gop_alloc(struct vnode *vp, off_t off, off_t len, int flags,kauth_cred_t cred);
int chfs_mountfs(struct vnode *devvp, struct mount *mp);
/* chfs_vnops.c */
extern int (**chfs_vnodeop_p)(void *);
extern int (**chfs_specop_p)(void *);
extern int (**chfs_fifoop_p)(void *);
int chfs_lookup(void *);
int chfs_create(void *);
int chfs_mknod(void *);
int chfs_open(void *);
int chfs_close(void *);
int chfs_access(void *);
int chfs_getattr(void *);
int chfs_setattr(void *);
int chfs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t);
int chfs_chmod(struct vnode *, int, kauth_cred_t);
int chfs_read(void *);
int chfs_write(void *);
int chfs_fsync(void *);
int chfs_remove(void *);
int chfs_link(void *);
int chfs_rename(void *);
int chfs_mkdir(void *);
int chfs_rmdir(void *);
int chfs_symlink(void *);
int chfs_readdir(void *);
int chfs_readlink(void *);
int chfs_inactive(void *);
int chfs_reclaim(void *);
int chfs_advlock(void *);
int chfs_strategy(void *);
int chfs_bmap(void *);
/* chfs_vnode.c */
struct vnode *chfs_vnode_lookup(struct chfs_mount *, ino_t);
int chfs_readvnode(struct mount *, ino_t, struct vnode **);
int chfs_readdirent(struct mount *, struct chfs_node_ref *,
struct chfs_inode *);
int chfs_makeinode(int, struct vnode *, struct vnode **,
struct componentname *, int );
void chfs_set_vnode_size(struct vnode *, size_t);
void chfs_change_size_free(struct chfs_mount *,
struct chfs_eraseblock *, int);
void chfs_change_size_dirty(struct chfs_mount *,
struct chfs_eraseblock *, int);
void chfs_change_size_unchecked(struct chfs_mount *,
struct chfs_eraseblock *, int);
void chfs_change_size_used(struct chfs_mount *,
struct chfs_eraseblock *, int);
void chfs_change_size_wasted(struct chfs_mount *,
struct chfs_eraseblock *, int);
/* chfs_vnode_cache.c */
struct chfs_vnode_cache **chfs_vnocache_hash_init(void);
void chfs_vnocache_hash_destroy(struct chfs_vnode_cache **);
void chfs_vnode_cache_set_state(struct chfs_mount *,
struct chfs_vnode_cache *, int);
struct chfs_vnode_cache* chfs_vnode_cache_get(
struct chfs_mount *, ino_t);
void chfs_vnode_cache_add(struct chfs_mount *,
struct chfs_vnode_cache *);
void chfs_vnode_cache_remove(struct chfs_mount *,
struct chfs_vnode_cache *);
/* chfs_wbuf.c */
int chfs_write_wbuf(struct chfs_mount*, const struct iovec *, long,
off_t, size_t *);
int chfs_flush_pending_wbuf(struct chfs_mount *);
/* chfs_write.c */
int chfs_write_flash_vnode(struct chfs_mount *, struct chfs_inode *, int);
int chfs_write_flash_dirent(struct chfs_mount *, struct chfs_inode *,
struct chfs_inode *, struct chfs_dirent *, ino_t, int);
int chfs_write_flash_dnode(struct chfs_mount *, struct vnode *,
struct buf *, struct chfs_full_dnode *);
int chfs_do_link(struct chfs_inode *, struct chfs_inode *, const char *, int, enum vtype);
int chfs_do_unlink(struct chfs_inode *, struct chfs_inode *, const char *, int);
/* chfs_subr.c */
size_t chfs_mem_info(bool);
struct chfs_dirent * chfs_dir_lookup(struct chfs_inode *,
struct componentname *);
int chfs_filldir (struct uio *, ino_t, const char *, int, enum vtype);
int chfs_chsize(struct vnode *, u_quad_t, kauth_cred_t);
int chfs_chflags(struct vnode *, int, kauth_cred_t);
void chfs_itimes(struct chfs_inode *, const struct timespec *,
const struct timespec *, const struct timespec *);
int chfs_update(struct vnode *, const struct timespec *,
const struct timespec *, int);
//int chfs_truncate(struct vnode *, off_t);
/*---------------------------------------------------------------------------*/
/* Some inline functions temporarily placed here */
static inline int
chfs_map_leb(struct chfs_mount *chmp, int lnr)
{
int err;
err = ebh_map_leb(chmp->chm_ebh, lnr);
if (err)
chfs_err("unmap leb %d failed, error: %d\n",lnr, err);
return err;
}
static inline int
chfs_unmap_leb(struct chfs_mount *chmp, int lnr)
{
int err;
err = ebh_unmap_leb(chmp->chm_ebh, lnr);
if (err)
chfs_err("unmap leb %d failed, error: %d\n",lnr, err);
return err;
}
static inline int
chfs_read_leb(struct chfs_mount *chmp, int lnr, char *buf,
int offset, int len, size_t *retlen)
{
int err;
err = ebh_read_leb(chmp->chm_ebh, lnr, buf, offset, len, retlen);
if (err)
chfs_err("read leb %d:%d failed, error: %d\n",lnr, offset, err);
return err;
}
static inline int chfs_write_leb(struct chfs_mount *chmp, int lnr, char *buf,
int offset, int len, size_t *retlen)
{
int err;
err = ebh_write_leb(chmp->chm_ebh, lnr, buf, offset, len, retlen);
if (err)
chfs_err("write leb %d:%d failed, error: %d\n",lnr, offset, err);
return err;
}
/******************************************************************************/
/* Code from dummyfs.h */
/******************************************************************************/
/* --------------------------------------------------------------------- */
#define CHFS_PAGES_RESERVED (4 * 1024 * 1024 / PAGE_SIZE)
static __inline size_t
CHFS_PAGES_MAX(struct chfs_mount *chmp)
{
size_t freepages;
freepages = chfs_mem_info(false);
if (freepages < CHFS_PAGES_RESERVED)
freepages = 0;
else
freepages -= CHFS_PAGES_RESERVED;
return MIN(chmp->chm_pages_max, freepages + chmp->chm_pages_used);
}
#define CHFS_ITIMES(ip, acc, mod, cre) \
while ((ip)->iflag & (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY)) \
chfs_itimes(ip, acc, mod, cre)
/* used for KASSERTs */
#define IMPLIES(a, b) (!(a) || (b))
#define IFF(a, b) (IMPLIES(a, b) && IMPLIES(b, a))
/*
struct chfs_node;
*/
/*
* Internal representation of a dummyfs directory entry.
*/
/*
struct chfs_dirent {
TAILQ_ENTRY(chfs_dirent) chd_entries;
uint16_t chd_namelen;
char * chd_name;
struct chfs_node * chd_node;
};
TAILQ_HEAD(chfs_dir, chfs_dirent);
*/
/*
* Internal representation of a dummyfs file system node.
*/
/*
struct chfs_node {
LIST_ENTRY(chfs_node) chn_entries;
enum vtype chn_type;
ino_t chn_id;
int chn_status;
#define CHFS_NODE_ACCESSED (1 << 1)
#define CHFS_NODE_MODIFIED (1 << 2)
#define CHFS_NODE_CHANGED (1 << 3)
off_t chn_size;
uid_t chn_uid;
gid_t chn_gid;
mode_t chn_mode;
int chn_flags;
nlink_t chn_links;
struct timespec chn_atime;
struct timespec chn_mtime;
struct timespec chn_ctime;
struct timespec chn_birthtime;
unsigned long chn_gen;
struct lockf * chn_lockf;
kmutex_t chn_vlock;
struct vnode * chn_vnode;
union {
struct {
dev_t chn_rdev;
} chn_dev;
struct {
struct chfs_node * chn_parent;
struct chfs_dir chn_dir;
off_t chn_readdir_lastn;
struct chfs_dirent * chn_readdir_lastp;
} chn_dir;
struct chn_lnk {
char * chn_link;
} chn_lnk;
struct chn_reg {
struct uvm_object * chn_aobj;
size_t chn_aobj_pages;
} chn_reg;
} chn_spec;
};
*/
/*
LIST_HEAD(chfs_node_list, chfs_node);
#define VTOCHN(vp) ((struct chfs_node *)(vp)->v_data)
#define CHNTOV(chnp) ((chnp)->chn_vnode)
*/
/*
* Ensures that the node pointed by 'node' is a directory and that its
* contents are consistent with respect to directories.
*/
/*
#ifdef someonefixthisplease
#define CHFS_VALIDATE_DIR(node) \
KASSERT((node)->chn_type == VDIR); \
KASSERT((node)->chn_size % sizeof(struct chfs_dirent) == 0); \
KASSERT((node)->chn_spec.chn_dir.chn_readdir_lastp == NULL || \
chfs_dircookie((node)->chn_spec.chn_dir.chn_readdir_lastp) == \
(node)->chn_spec.chn_dir.chn_readdir_lastn);
#else
#define CHFS_VALIDATE_DIR(node) \
KASSERT((node)->chn_type == VDIR); \
KASSERT((node)->chn_size % sizeof(struct chfs_dirent) == 0);
#endif
*/
/* Returns the available space for the given file system. */
/*
#define CHFS_PAGES_AVAIL(dmp) \
((ssize_t)(CHFS_PAGES_MAX(dmp) - (dmp)->chm_pages_used))
static __inline
struct chfs_node *
VP_TO_CHFS_NODE(struct vnode *vp)
{
struct chfs_node *node;
#ifdef KASSERT
KASSERT((vp) != NULL && (vp)->v_data != NULL);
#endif
node = (struct chfs_node *)vp->v_data;
return node;
}
static __inline
struct chfs_node *
VP_TO_CHFS_DIR(struct vnode *vp)
{
struct chfs_node *node;
node = VP_TO_CHFS_NODE(vp);
#ifdef KASSERT
CHFS_VALIDATE_DIR(node);
#endif
return node;
}
*/
#endif /* __CHFS_H__ */

53
sys/ufs/chfs/chfs_args.h Normal file
View File

@ -0,0 +1,53 @@
/* $NetBSD: chfs_args.h,v 1.1 2011/11/24 15:51:31 ahoka Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
* University of Szeged, Hungary
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* 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.
*/
#ifndef _FS_CHFS_CHFS_ARGS_H_
#define _FS_CHFS_CHFS_ARGS_H_
#define CHFS_ARGS_VERSION 1
/**
* struct chfs_args - arguments needed when mounting filesystem
* @fl_index: index of the flash device in the flash layer
*/
struct chfs_args {
//int ca_version;
char *fspec;
int fl_index;
/* Root node attributes. */
/*uid_t ca_root_uid;
gid_t ca_root_gid;
mode_t ca_root_mode;*/
};
#endif /* _FS_CHFS_CHFS_ARGS_H_ */

404
sys/ufs/chfs/chfs_build.c Normal file
View File

@ -0,0 +1,404 @@
/* $NetBSD: chfs_build.c,v 1.1 2011/11/24 15:51:31 ahoka Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
* University of Szeged, Hungary
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* 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 "chfs.h"
//#include </root/xipffs/netbsd.chfs/chfs.h>
void
chfs_calc_trigger_levels(struct chfs_mount *chmp)
{
uint32_t size;
chmp->chm_resv_blocks_deletion = 2;
size = chmp->chm_ebh->flash_size / 50; //2% of flash size
size += chmp->chm_ebh->peb_nr * 100;
size += chmp->chm_ebh->eb_size - 1;
chmp->chm_resv_blocks_write =
chmp->chm_resv_blocks_deletion + (size / chmp->chm_ebh->eb_size);
chmp->chm_resv_blocks_gctrigger = chmp->chm_resv_blocks_write + 1;
chmp->chm_resv_blocks_gcmerge = chmp->chm_resv_blocks_deletion + 1;
chmp->chm_vdirty_blocks_gctrigger = chmp->chm_resv_blocks_gctrigger * 10;
chmp->chm_nospc_dirty =
chmp->chm_ebh->eb_size + (chmp->chm_ebh->flash_size / 100);
}
/**
* chfs_build_set_vnodecache_nlink - set pvno and nlink in vnodecaches
* @chmp: CHFS main descriptor structure
* @vc: vnode cache
* This function travels @vc's directory entries and sets the pvno and nlink
* attribute of the vnode where the dirent's vno points.
*/
void
chfs_build_set_vnodecache_nlink(struct chfs_mount *chmp,
struct chfs_vnode_cache *vc)
{
struct chfs_dirent *fd;
//dbg("set nlink\n");
// for (fd = vc->scan_dirents; fd; fd = fd->next) {
TAILQ_FOREACH(fd, &vc->scan_dirents, fds) {
struct chfs_vnode_cache *child_vc;
if (!fd->vno)
continue;
mutex_enter(&chmp->chm_lock_vnocache);
child_vc = chfs_vnode_cache_get(chmp, fd->vno);
mutex_exit(&chmp->chm_lock_vnocache);
if (!child_vc) {
chfs_mark_node_obsolete(chmp, fd->nref);
continue;
}
if (fd->type == VDIR) {
if (child_vc->nlink < 1)
child_vc->nlink = 1;
if (child_vc->pvno) {
chfs_err("found a hard link: child dir: %s"
", (vno: %llu) of dir vno: %llu\n",
fd->name, fd->vno, vc->vno);
} else {
//dbg("child_vc->pvno =
// vc->vno; pvno = %d\n", child_vc->pvno);
child_vc->pvno = vc->vno;
}
}
child_vc->nlink++;
//dbg("child_vc->nlink++;\n");
//child_vc->nlink++;
vc->nlink++;
}
}
/**
* chfs_build_remove_unlinked vnode
*/
/* static */
void
chfs_build_remove_unlinked_vnode(struct chfs_mount *chmp,
struct chfs_vnode_cache *vc,
// struct chfs_dirent **unlinked)
struct chfs_dirent_list *unlinked)
{
struct chfs_node_ref *nref;
struct chfs_dirent *fd, *tmpfd;
dbg("START\n");
dbg("vno: %llu\n", vc->vno);
nref = vc->dnode;
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
// The vnode cache is at the end of the data node's chain
while (nref != (struct chfs_node_ref *)vc) {
struct chfs_node_ref *next = nref->nref_next;
dbg("mark dnode\n");
chfs_mark_node_obsolete(chmp, nref);
nref = next;
}
nref = vc->dirents;
// The vnode cache is at the end of the dirent node's chain
while (nref != (struct chfs_node_ref *)vc) {
struct chfs_node_ref *next = nref->nref_next;
dbg("mark dirent\n");
chfs_mark_node_obsolete(chmp, nref);
nref = next;
}
if (!TAILQ_EMPTY(&vc->scan_dirents)) {
TAILQ_FOREACH_SAFE(fd, &vc->scan_dirents, fds, tmpfd) {
// while (vc->scan_dirents) {
struct chfs_vnode_cache *child_vc;
// fd = vc->scan_dirents;
dbg("dirent dump:\n");
dbg(" ->vno: %llu\n", fd->vno);
dbg(" ->version: %llu\n", fd->version);
dbg(" ->nhash: 0x%x\n", fd->nhash);
dbg(" ->nsize: %d\n", fd->nsize);
dbg(" ->name: %s\n", fd->name);
dbg(" ->type: %d\n", fd->type);
// vc->scan_dirents = fd->next;
TAILQ_REMOVE(&vc->scan_dirents, fd, fds);
if (!fd->vno) {
chfs_free_dirent(fd);
continue;
}
mutex_enter(&chmp->chm_lock_vnocache);
child_vc = chfs_vnode_cache_get(chmp, fd->vno);
mutex_exit(&chmp->chm_lock_vnocache);
if (!child_vc) {
chfs_free_dirent(fd);
continue;
}
/**
* Decrease nlink in child. If it is 0, add to unlinked
* dirents or just free it otherwise.
*/
child_vc->nlink--;
if (!child_vc->nlink) {
//dbg("nlink is 0\n");
// fd->next = *unlinked;
// *unlinked = fd;
// XXX HEAD or TAIL?
// original code did HEAD, but we could add
// it to the TAIL easily with TAILQ.
TAILQ_INSERT_TAIL(unlinked, fd, fds);
} else {
chfs_free_dirent(fd);
}
}
} else {
dbg("there are no scan dirents\n");
}
nref = vc->v;
while ((struct chfs_vnode_cache *)nref != vc) {
if (!CHFS_REF_OBSOLETE(nref))
chfs_mark_node_obsolete(chmp, nref);
nref = nref->nref_next;
}
mutex_enter(&chmp->chm_lock_vnocache);
if (vc->vno != CHFS_ROOTINO)
chfs_vnode_cache_set_state(chmp, vc, VNO_STATE_UNCHECKED);
mutex_exit(&chmp->chm_lock_vnocache);
dbg("END\n");
}
/**
* chfs_build_filesystem - build in-memory representation of filesystem
* @chmp: super block information
*
* Step 1:
* This function scans through the eraseblocks mapped in EBH.
* During scan builds up the map of vnodes and directory entries and puts them
* into the vnode_cache.
* Step 2:
* Scans the directory tree and set the nlink in the vnode caches.
* Step 3:
* Scans vnode caches with nlink = 0
*/
int
chfs_build_filesystem(struct chfs_mount *chmp)
{
int i,err = 0;
struct chfs_vnode_cache *vc;
struct chfs_dirent *fd, *tmpfd;
// struct chfs_dirent *unlinked = NULL;
struct chfs_node_ref **nref;
struct chfs_dirent_list unlinked;
struct chfs_vnode_cache *notregvc;
TAILQ_INIT(&unlinked);
mutex_enter(&chmp->chm_lock_mountfields);
/**
* Step 1
*/
chmp->chm_flags |= CHFS_MP_FLAG_SCANNING;
for (i = 0; i < chmp->chm_ebh->peb_nr; i++) {
//dbg("processing block: %d\n", i);
chmp->chm_blocks[i].lnr = i;
chmp->chm_blocks[i].free_size = chmp->chm_ebh->eb_size;
//If the LEB is add to free list skip it.
if (chmp->chm_ebh->lmap[i] < 0) {
//dbg("block %d is unmapped\n", i);
TAILQ_INSERT_TAIL(&chmp->chm_free_queue,
&chmp->chm_blocks[i], queue);
chmp->chm_nr_free_blocks++;
continue;
}
err = chfs_scan_eraseblock(chmp, &chmp->chm_blocks[i]);
switch (err) {
case CHFS_BLK_STATE_FREE:
chmp->chm_nr_free_blocks++;
TAILQ_INSERT_TAIL(&chmp->chm_free_queue,
&chmp->chm_blocks[i], queue);
break;
case CHFS_BLK_STATE_CLEAN:
TAILQ_INSERT_TAIL(&chmp->chm_clean_queue,
&chmp->chm_blocks[i], queue);
break;
case CHFS_BLK_STATE_PARTDIRTY:
//dbg("free size: %d\n", chmp->chm_blocks[i].free_size);
if (chmp->chm_blocks[i].free_size > chmp->chm_wbuf_pagesize &&
(!chmp->chm_nextblock ||
chmp->chm_blocks[i].free_size >
chmp->chm_nextblock->free_size)) {
/* convert the old nextblock's free size to
* dirty and put it on a list */
if (chmp->chm_nextblock) {
err = chfs_close_eraseblock(chmp,
chmp->chm_nextblock);
if (err)
return err;
}
chmp->chm_nextblock = &chmp->chm_blocks[i];
} else {
/* convert the scanned block's free size to
* dirty and put it on a list */
err = chfs_close_eraseblock(chmp,
&chmp->chm_blocks[i]);
if (err)
return err;
}
break;
case CHFS_BLK_STATE_ALLDIRTY:
/*
* The block has a valid EBH header, but it doesn't
* contain any valid data.
*/
TAILQ_INSERT_TAIL(&chmp->chm_erase_pending_queue,
&chmp->chm_blocks[i], queue);
chmp->chm_nr_erasable_blocks++;
break;
default:
/* It was an error, unknown state */
break;
}
}
chmp->chm_flags &= ~CHFS_MP_FLAG_SCANNING;
//TODO need bad block check (and bad block handling in EBH too!!)
/* Now EBH only checks block is bad during its scan operation.
* Need check at erase + write + read...
*/
/**
* Step 2
*/
chmp->chm_flags |= CHFS_MP_FLAG_BUILDING;
for (i = 0; i < VNODECACHE_SIZE; i++) {
vc = chmp->chm_vnocache_hash[i];
while (vc) {
dbg("vc->vno: %llu\n", vc->vno);
if (!TAILQ_EMPTY(&vc->scan_dirents))
chfs_build_set_vnodecache_nlink(chmp, vc);
vc = vc->next;
}
}
/**
* Step 3
* Scan for vnodes with 0 nlink.
*/
for (i = 0; i < VNODECACHE_SIZE; i++) {
vc = chmp->chm_vnocache_hash[i];
while (vc) {
if (vc->nlink) {
vc = vc->next;
continue;
}
//dbg("remove unlinked start i: %d\n", i);
chfs_build_remove_unlinked_vnode(chmp,
vc, &unlinked);
//dbg("remove unlinked end\n");
vc = vc->next;
}
}
/* Remove the newly unlinked vnodes. They are on the unlinked list */
TAILQ_FOREACH_SAFE(fd, &unlinked, fds, tmpfd) {
// while (unlinked) {
// fd = unlinked;
// unlinked = fd->next;
TAILQ_REMOVE(&unlinked, fd, fds);
mutex_enter(&chmp->chm_lock_vnocache);
vc = chfs_vnode_cache_get(chmp, fd->vno);
mutex_exit(&chmp->chm_lock_vnocache);
if (vc) {
chfs_build_remove_unlinked_vnode(chmp,
vc, &unlinked);
}
chfs_free_dirent(fd);
}
chmp->chm_flags &= ~CHFS_MP_FLAG_BUILDING;
/* Free all dirents */
for (i = 0; i < VNODECACHE_SIZE; i++) {
vc = chmp->chm_vnocache_hash[i];
while (vc) {
TAILQ_FOREACH_SAFE(fd, &vc->scan_dirents, fds, tmpfd) {
// while (vc->scan_dirents) {
// fd = vc->scan_dirents;
// vc->scan_dirents = fd->next;
TAILQ_REMOVE(&vc->scan_dirents, fd, fds);
if (fd->vno == 0) {
//for (nref = &vc->dirents;
// *nref != fd->nref;
// nref = &((*nref)->next));
nref = &fd->nref;
*nref = fd->nref->nref_next;
//fd->nref->nref_next = NULL;
} else if (fd->type == VDIR) {
//set state every non-VREG file's vc
mutex_enter(&chmp->chm_lock_vnocache);
notregvc =
chfs_vnode_cache_get(chmp,
fd->vno);
chfs_vnode_cache_set_state(chmp,
notregvc, VNO_STATE_PRESENT);
mutex_exit(&chmp->chm_lock_vnocache);
}
chfs_free_dirent(fd);
}
// vc->scan_dirents = NULL;
KASSERT(TAILQ_EMPTY(&vc->scan_dirents));
vc = vc->next;
}
}
//Set up chmp->chm_wbuf_ofs for the first write
if (chmp->chm_nextblock) {
dbg("free_size: %d\n", chmp->chm_nextblock->free_size);
chmp->chm_wbuf_ofs = chmp->chm_ebh->eb_size -
chmp->chm_nextblock->free_size;
} else {
chmp->chm_wbuf_ofs = 0xffffffff;
}
mutex_exit(&chmp->chm_lock_mountfields);
return 0;
}

137
sys/ufs/chfs/chfs_erase.c Normal file
View File

@ -0,0 +1,137 @@
/* $NetBSD: chfs_erase.c,v 1.1 2011/11/24 15:51:31 ahoka Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
* University of Szeged, Hungary
* Copyright (c) 2010 David Tengeri <dtengeri@inf.u-szeged.hu>
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* 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.
*/
/*
* chfs_erase.c
*
* Copyright (C) 2010 David Tengeri <dtengeri@inf.u-szeged.hu>,
* ...
* University of Szeged, Hungary
*/
#include "chfs.h"
/**
* chfs_remap_leb - unmap and then map a leb
* @chmp: chfs mount structure
*
* This function gets an eraseblock from the erasable queue, unmaps it through
* EBH and maps another eraseblock to the same LNR.
* EBH will find a free eraseblock if any or will erase one if there isn't any
* free, just dirty block.
*
* Returns zero on case of success, errorcode otherwise.
*
* Needs more brainstorming here.
*/
int
chfs_remap_leb(struct chfs_mount *chmp)
{
int err;
struct chfs_eraseblock *cheb;
dbg("chfs_remap_leb\n");
uint32_t dirty, unchecked, used, free, wasted;
//dbg("chmp->chm_nr_erasable_blocks: %d\n", chmp->chm_nr_erasable_blocks);
//dbg("ltree: %p ecl: %p\n", &chmp->chm_ebh->ltree_lock, &chmp->chm_lock_sizes);
KASSERT(!rw_write_held(&chmp->chm_lock_wbuf));
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
KASSERT(mutex_owned(&chmp->chm_lock_sizes));
if (!chmp->chm_nr_erasable_blocks) {
//TODO
/* We don't have any erasable blocks, need to check if there are
* blocks on erasable_pending_wbuf_queue, flush the data and then
* we can remap it.
* If there aren't any blocks on that list too, we need to GC?
*/
if (!TAILQ_EMPTY(&chmp->chm_erasable_pending_wbuf_queue)) {
cheb = TAILQ_FIRST(&chmp->chm_erasable_pending_wbuf_queue);
TAILQ_REMOVE(&chmp->chm_erasable_pending_wbuf_queue, cheb, queue);
if (chmp->chm_wbuf_len) {
mutex_exit(&chmp->chm_lock_sizes);
chfs_flush_pending_wbuf(chmp);
mutex_enter(&chmp->chm_lock_sizes);
}
TAILQ_INSERT_TAIL(&chmp->chm_erase_pending_queue, cheb, queue);
chmp->chm_nr_erasable_blocks++;
} else {
/* We can't delete any block. */
//FIXME should we return ENOSPC?
return ENOSPC;
}
}
cheb = TAILQ_FIRST(&chmp->chm_erase_pending_queue);
TAILQ_REMOVE(&chmp->chm_erase_pending_queue, cheb, queue);
chmp->chm_nr_erasable_blocks--;
dirty = cheb->dirty_size;
unchecked = cheb->unchecked_size;
used = cheb->used_size;
free = cheb->free_size;
wasted = cheb->wasted_size;
// Free allocated node references for this eraseblock
chfs_free_node_refs(cheb);
err = chfs_unmap_leb(chmp, cheb->lnr);
if (err)
return err;
err = chfs_map_leb(chmp, cheb->lnr);
if (err)
return err;
// Reset state to default and change chmp sizes too
chfs_change_size_dirty(chmp, cheb, -dirty);
chfs_change_size_unchecked(chmp, cheb, -unchecked);
chfs_change_size_used(chmp, cheb, -used);
chfs_change_size_free(chmp, cheb, chmp->chm_ebh->eb_size - free);
chfs_change_size_wasted(chmp, cheb, -wasted);
KASSERT(cheb->dirty_size == 0);
KASSERT(cheb->unchecked_size == 0);
KASSERT(cheb->used_size == 0);
KASSERT(cheb->free_size == chmp->chm_ebh->eb_size);
KASSERT(cheb->wasted_size == 0);
cheb->first_node = NULL;
cheb->last_node = NULL;
//put it to free_queue
TAILQ_INSERT_TAIL(&chmp->chm_free_queue, cheb, queue);
chmp->chm_nr_free_blocks++;
dbg("remaped (free: %d, erasable: %d)\n", chmp->chm_nr_free_blocks, chmp->chm_nr_erasable_blocks);
KASSERT(!TAILQ_EMPTY(&chmp->chm_free_queue));
return 0;
}

1235
sys/ufs/chfs/chfs_gc.c Normal file

File diff suppressed because it is too large Load Diff

220
sys/ufs/chfs/chfs_ihash.c Normal file
View File

@ -0,0 +1,220 @@
/* $NetBSD: chfs_ihash.c,v 1.1 2011/11/24 15:51:31 ahoka Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
* University of Szeged, Hungary
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* 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 "chfs.h"
/*
* Structures associated with inode cacheing.
*/
static LIST_HEAD(ihashhead, chfs_inode) *chfs_ihashtbl;
static u_long chfs_ihash; /* size of hash table - 1 */
#define INOHASH(device, inum) (((device) + (inum)) & chfs_ihash)
kmutex_t chfs_ihash_lock;
kmutex_t chfs_hashlock;
/*
* Initialize inode hash table.
*/
void
chfs_ihashinit(void)
{
dbg("initing\n");
mutex_init(&chfs_hashlock, MUTEX_DEFAULT, IPL_NONE);
mutex_init(&chfs_ihash_lock, MUTEX_DEFAULT, IPL_NONE);
chfs_ihashtbl = hashinit(desiredvnodes,
HASH_LIST, true, &chfs_ihash);
}
/*
* Reinitialize inode hash table.
*/
void
chfs_ihashreinit(void)
{
struct chfs_inode *ip;
struct ihashhead *oldhash, *hash;
u_long oldmask, mask, val;
int i;
dbg("reiniting\n");
hash = hashinit(desiredvnodes, HASH_LIST, true, &mask);
mutex_enter(&chfs_ihash_lock);
oldhash = chfs_ihashtbl;
oldmask = chfs_ihash;
chfs_ihashtbl = hash;
chfs_ihash = mask;
for (i = 0; i <= oldmask; i++) {
while ((ip = LIST_FIRST(&oldhash[i])) != NULL) {
LIST_REMOVE(ip, hash_entry);
val = INOHASH(ip->dev, ip->ino);
LIST_INSERT_HEAD(&hash[val], ip, hash_entry);
}
}
mutex_exit(&chfs_ihash_lock);
hashdone(oldhash, HASH_LIST, oldmask);
}
/*
* Free inode hash table.
*/
void
chfs_ihashdone(void)
{
dbg("destroying\n");
hashdone(chfs_ihashtbl, HASH_LIST, chfs_ihash);
mutex_destroy(&chfs_hashlock);
mutex_destroy(&chfs_ihash_lock);
}
/*
* Use the device/inum pair to find the incore inode, and return a pointer
* to it. If it is in core, return it, even if it is locked.
*/
struct vnode *
chfs_ihashlookup(dev_t dev, ino_t inum)
{
struct chfs_inode *ip;
struct ihashhead *ipp;
dbg("dev: %ju, inum: %ju\n", (uintmax_t )dev, (uintmax_t )inum);
KASSERT(mutex_owned(&chfs_ihash_lock));
ipp = &chfs_ihashtbl[INOHASH(dev, inum)];
LIST_FOREACH(ip, ipp, hash_entry) {
if (inum == ip->ino && dev == ip->dev) {
break;
}
}
if (ip) {
return (ITOV(ip));
}
return (NULLVP);
}
/*
* Use the device/inum pair to find the incore inode, and return a pointer
* to it. If it is in core, but locked, wait for it.
*/
struct vnode *
chfs_ihashget(dev_t dev, ino_t inum, int flags)
{
struct ihashhead *ipp;
struct chfs_inode *ip;
struct vnode *vp;
dbg("search for ino\n");
loop:
mutex_enter(&chfs_ihash_lock);
ipp = &chfs_ihashtbl[INOHASH(dev, inum)];
dbg("ipp: %p, chfs_ihashtbl: %p, ihash: %lu\n",
ipp, chfs_ihashtbl, chfs_ihash);
LIST_FOREACH(ip, ipp, hash_entry) {
dbg("ip: %p\n", ip);
if (inum == ip->ino && dev == ip->dev) {
// printf("chfs_ihashget: found inode: %p\n", ip);
vp = ITOV(ip);
KASSERT(vp != NULL);
//dbg("found\n");
if (VOP_ISLOCKED(vp) == LK_EXCLUSIVE) {
//dbg("wait for #%llu\n", ip->ino);
mutex_exit(&chfs_ihash_lock);
goto loop;
}
/*
if (VOP_ISLOCKED(vp))
dbg("locked\n");
else
dbg("isn't locked\n");
*/
if (flags == 0) {
//dbg("no flags\n");
mutex_exit(&chfs_ihash_lock);
} else {
//dbg("vget\n");
mutex_enter(vp->v_interlock);
mutex_exit(&chfs_ihash_lock);
if (vget(vp, flags)) {
goto loop;
}
//dbg("got it\n");
}
//dbg("return\n");
return (vp);
}
}
//dbg("not found\n");
mutex_exit(&chfs_ihash_lock);
return (NULL);
}
/*
* Insert the inode into the hash table, and return it locked.
*/
void
chfs_ihashins(struct chfs_inode *ip)
{
struct ihashhead *ipp;
dbg("ip: %p\n", ip);
KASSERT(mutex_owned(&chfs_hashlock));
/* lock the inode, then put it on the appropriate hash list */
VOP_LOCK(ITOV(ip), LK_EXCLUSIVE);
mutex_enter(&chfs_ihash_lock);
ipp = &chfs_ihashtbl[INOHASH(ip->dev, ip->ino)];
LIST_INSERT_HEAD(ipp, ip, hash_entry);
mutex_exit(&chfs_ihash_lock);
}
/*
* Remove the inode from the hash table.
*/
void
chfs_ihashrem(struct chfs_inode *ip)
{
dbg("ip: %p\n", ip);
mutex_enter(&chfs_ihash_lock);
LIST_REMOVE(ip, hash_entry);
mutex_exit(&chfs_ihash_lock);
}

136
sys/ufs/chfs/chfs_inode.h Normal file
View File

@ -0,0 +1,136 @@
/* $NetBSD: chfs_inode.h,v 1.1 2011/11/24 15:51:31 ahoka Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
* University of Szeged, Hungary
* Copyright (C) 2010 Tamas Toth <ttoth@inf.u-szeged.hu>
* Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* 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.
*/
#ifndef __CHFS_INODE_H__
#define __CHFS_INODE_H__
#include <sys/vnode.h>
#include <sys/stat.h>
#include <ufs/ufs/ufsmount.h>
#include <miscfs/genfs/genfs_node.h>
struct chfs_inode
{
kmutex_t inode_lock; /* lock the fields of chfs_inode */
LIST_ENTRY(chfs_inode) hash_entry; /* Hash chain. */
struct ufsmount *ump; /* ufs mount - TODO we should remove it */
struct chfs_mount *chmp; /* chfs mount point - TODO we should remove it */
struct vnode *vp; /* vnode associated with this inode */
ino_t ino; /* vnode identifier number */
struct vnode *devvp; /* vnode for block I/O */
dev_t dev; /* device associated with the inode */
struct chfs_vnode_cache *chvc; /* vnode cache of this node */
struct chfs_dirent *fd; /* full dirent of this node */
// struct chfs_dirent *dents; /* directory entries */
struct chfs_dirent_list dents;
struct rb_tree fragtree; /* fragtree of inode */
uint64_t version; /* version number */
//uint64_t highest_version; /* highest vers. num. (used at data nodes) */
uint32_t mode; /* mode */
//int16_t nlink; /* link count */
uint64_t size; /* file byte count */
uint64_t write_size; /* increasing while write the file out to the flash */
uint32_t uid; /* file owner */
uint32_t gid; /* file group */
uint32_t atime; /* access time */
uint32_t mtime; /* modify time */
uint32_t ctime; /* creation time */
uint32_t iflag; /* flags, see below */
uint32_t flags; /* status flags (chflags) */
dev_t rdev; /* used if type is VCHR or VBLK or VFIFO*/
char *target; /* used if type is VLNK */
};
/* These flags are kept in chfs_inode->iflag. */
#define IN_ACCESS 0x0001 /* 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_MODIFY 0x2000 /* Modification time update request. */
#define IN_MODIFIED 0x0008 /* Inode has been modified. */
#define IN_ACCESSED 0x0010 /* Inode has been accessed. */
#define IN_RENAME 0x0020 /* Inode is being renamed. */
#define IN_SHLOCK 0x0040 /* File has shared lock. */
#define IN_EXLOCK 0x0080 /* File has exclusive lock. */
#define IN_CLEANING 0x0100 /* LFS: file is being cleaned */
#define IN_ADIROP 0x0200 /* LFS: dirop in progress */
#define IN_SPACECOUNTED 0x0400 /* Blocks to be freed in free count. */
#define IN_PAGING 0x1000 /* LFS: file is on paging queue */
#ifdef VTOI
# undef VTOI
#endif
#ifdef ITOV
# undef ITOV
#endif
#define VTOI(vp) ((struct chfs_inode *)(vp)->v_data)
#define ITOV(ip) ((ip)->vp)
/* copied from ufs_dinode.h */
#define NDADDR 12 /* Direct addresses in inode. */
#define ROOTINO ((ino_t)2)
/* File permissions. */
#define IEXEC 0000100 /* Executable. */
#define IWRITE 0000200 /* Writable. */
#define IREAD 0000400 /* Readable. */
#define ISVTX 0001000 /* Sticky bit. */
#define ISGID 0002000 /* Set-gid. */
#define ISUID 0004000 /* Set-uid. */
/* File types. */
#define IFMT 0170000 /* Mask of file type. */
#define IFIFO 0010000 /* Named pipe (fifo). */
#define IFCHR 0020000 /* Character device. */
#define IFDIR 0040000 /* Directory file. */
#define IFBLK 0060000 /* Block device. */
#define IFREG 0100000 /* Regular file. */
#define IFLNK 0120000 /* Symbolic link. */
#define IFSOCK 0140000 /* UNIX domain socket. */
#define IFWHT 0160000 /* Whiteout. */
#endif /* __CHFS_INODE_H__ */

396
sys/ufs/chfs/chfs_malloc.c Normal file
View File

@ -0,0 +1,396 @@
/* $NetBSD: chfs_malloc.c,v 1.1 2011/11/24 15:51:31 ahoka Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
* University of Szeged, Hungary
* Copyright (C) 2010 Tamas Toth <ttoth@inf.u-szeged.hu>
* Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* 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 "chfs.h"
#include <sys/pool.h>
pool_cache_t chfs_vnode_cache;
pool_cache_t chfs_nrefs_cache;
pool_cache_t chfs_flash_vnode_cache;
pool_cache_t chfs_flash_dirent_cache;
pool_cache_t chfs_flash_dnode_cache;
pool_cache_t chfs_node_frag_cache;
pool_cache_t chfs_tmp_dnode_cache;
pool_cache_t chfs_tmp_dnode_info_cache;
int
chfs_alloc_pool_caches()
{
chfs_vnode_cache = pool_cache_init(
sizeof(struct chfs_vnode_cache),
0, 0, 0, "chfs_vnode_cache", NULL, IPL_NONE, NULL, NULL,
NULL);
if (!chfs_vnode_cache)
goto err_vnode;
chfs_nrefs_cache = pool_cache_init(
(REFS_BLOCK_LEN + 1) * sizeof(struct chfs_node_ref), 0, 0,
0, "chfs_nrefs_pool", NULL, IPL_NONE, NULL, NULL, NULL);
if (!chfs_nrefs_cache)
goto err_nrefs;
chfs_flash_vnode_cache = pool_cache_init(
sizeof(struct chfs_flash_vnode), 0, 0, 0,
"chfs_flash_vnode_pool", NULL, IPL_NONE, NULL, NULL, NULL);
if (!chfs_flash_vnode_cache)
goto err_flash_vnode;
chfs_flash_dirent_cache = pool_cache_init(
sizeof(struct chfs_flash_dirent_node), 0, 0, 0,
"chfs_flash_dirent_pool", NULL, IPL_NONE, NULL, NULL, NULL);
if (!chfs_flash_dirent_cache)
goto err_flash_dirent;
chfs_flash_dnode_cache = pool_cache_init(
sizeof(struct chfs_flash_data_node), 0, 0, 0,
"chfs_flash_dnode_pool", NULL, IPL_NONE, NULL, NULL, NULL);
if (!chfs_flash_dnode_cache)
goto err_flash_dnode;
chfs_node_frag_cache = pool_cache_init(
sizeof(struct chfs_node_frag), 0, 0, 0,
"chfs_node_frag_pool", NULL, IPL_NONE, NULL, NULL, NULL);
if (!chfs_node_frag_cache)
goto err_node_frag;
chfs_tmp_dnode_cache = pool_cache_init(
sizeof(struct chfs_tmp_dnode), 0, 0, 0,
"chfs_tmp_dnode_pool", NULL, IPL_NONE, NULL, NULL, NULL);
if (!chfs_tmp_dnode_cache)
goto err_tmp_dnode;
chfs_tmp_dnode_info_cache = pool_cache_init(
sizeof(struct chfs_tmp_dnode_info), 0, 0, 0,
"chfs_tmp_dnode_info_pool", NULL, IPL_NONE, NULL, NULL, NULL);
if (!chfs_tmp_dnode_info_cache)
goto err_tmp_dnode_info;
return 0;
err_tmp_dnode_info:
pool_cache_destroy(chfs_tmp_dnode_cache);
err_tmp_dnode:
pool_cache_destroy(chfs_node_frag_cache);
err_node_frag:
pool_cache_destroy(chfs_flash_dnode_cache);
err_flash_dnode:
pool_cache_destroy(chfs_flash_dirent_cache);
err_flash_dirent:
pool_cache_destroy(chfs_flash_vnode_cache);
err_flash_vnode:
pool_cache_destroy(chfs_nrefs_cache);
err_nrefs:
pool_cache_destroy(chfs_vnode_cache);
err_vnode:
return ENOMEM;
}
void
chfs_destroy_pool_caches()
{
if (chfs_vnode_cache)
pool_cache_destroy(chfs_vnode_cache);
if (chfs_nrefs_cache)
pool_cache_destroy(chfs_nrefs_cache);
if (chfs_flash_vnode_cache)
pool_cache_destroy(chfs_flash_vnode_cache);
if (chfs_flash_dirent_cache)
pool_cache_destroy(chfs_flash_dirent_cache);
if (chfs_flash_dnode_cache)
pool_cache_destroy(chfs_flash_dnode_cache);
if (chfs_node_frag_cache)
pool_cache_destroy(chfs_node_frag_cache);
if (chfs_tmp_dnode_cache)
pool_cache_destroy(chfs_tmp_dnode_cache);
if (chfs_tmp_dnode_info_cache)
pool_cache_destroy(chfs_tmp_dnode_info_cache);
}
struct chfs_vnode_cache *
chfs_vnode_cache_alloc(ino_t vno)
{
struct chfs_vnode_cache* vc;
vc = pool_cache_get(chfs_vnode_cache, PR_WAITOK);
memset(vc, 0, sizeof(*vc));
vc->vno = vno;
vc->v = (void *)vc;
vc->dirents = (void *)vc;
vc->dnode = (void *)vc;
TAILQ_INIT(&vc->scan_dirents);
vc->highest_version = 0;
return vc;
}
void
chfs_vnode_cache_free(struct chfs_vnode_cache *vc)
{
//kmem_free(vc->vno_version, sizeof(uint64_t));
pool_cache_put(chfs_vnode_cache, vc);
}
/**
* chfs_alloc_refblock - allocating a refblock
*
* Returns a pointer of the first element in the block.
*
* We are not allocating just one node ref, instead we allocating REFS_BLOCK_LEN
* number of node refs, the last element will be a pointer to the next block.
* We do this, because we need a chain of nodes which have been ordered by the
* physical address of them.
*
*/
struct chfs_node_ref*
chfs_alloc_refblock(void)
{
int i;
struct chfs_node_ref *nref;
nref = pool_cache_get(chfs_nrefs_cache, PR_WAITOK);
for (i = 0; i < REFS_BLOCK_LEN; i++) {
nref[i].nref_lnr = REF_EMPTY_NODE;
nref[i].nref_next = NULL;
}
i = REFS_BLOCK_LEN;
nref[i].nref_lnr = REF_LINK_TO_NEXT;
nref[i].nref_next = NULL;
return nref;
}
/**
* chfs_free_refblock - freeing a refblock
*/
void
chfs_free_refblock(struct chfs_node_ref *nref)
{
pool_cache_put(chfs_nrefs_cache, nref);
}
/**
* chfs_alloc_node_ref - allocating a node ref from a refblock
* @cheb: eraseblock information structure
*
* Allocating a node ref from a refblock, it there isn't any free element in the
* block, a new block will be allocated and be linked to the current block.
*/
struct chfs_node_ref*
chfs_alloc_node_ref(struct chfs_eraseblock *cheb)
{
struct chfs_node_ref *nref, *new, *old;
old = cheb->last_node;
nref = cheb->last_node;
if (!nref) {
//There haven't been any nref allocated for this block yet
nref = chfs_alloc_refblock();
cheb->first_node = nref;
cheb->last_node = nref;
nref->nref_lnr = cheb->lnr;
KASSERT(cheb->lnr == nref->nref_lnr);
return nref;
}
nref++;
if (nref->nref_lnr == REF_LINK_TO_NEXT) {
new = chfs_alloc_refblock();
nref->nref_next = new;
nref = new;
}
cheb->last_node = nref;
nref->nref_lnr = cheb->lnr;
KASSERT(old->nref_lnr == nref->nref_lnr &&
nref->nref_lnr == cheb->lnr);
return nref;
}
/**
* chfs_free_node_refs - freeing an eraseblock's node refs
* @cheb: eraseblock information structure
*/
void
chfs_free_node_refs(struct chfs_eraseblock *cheb)
{
struct chfs_node_ref *nref, *block;
block = nref = cheb->first_node;
while (nref) {
if (nref->nref_lnr == REF_LINK_TO_NEXT) {
nref = nref->nref_next;
chfs_free_refblock(block);
block = nref;
continue;
}
nref++;
}
}
struct chfs_dirent*
chfs_alloc_dirent(int namesize)
{
struct chfs_dirent *ret;
size_t size = sizeof(struct chfs_dirent) + namesize;
ret = kmem_alloc(size, KM_SLEEP);
//ret->alloc_size = size;
return ret;
}
void
chfs_free_dirent(struct chfs_dirent *dirent)
{
//size_t size = dirent->alloc_size;
size_t size = sizeof(struct chfs_dirent) + dirent->nsize + 1;
kmem_free(dirent, size);
}
struct chfs_full_dnode*
chfs_alloc_full_dnode()
{
struct chfs_full_dnode *ret;
ret = kmem_alloc(sizeof(struct chfs_full_dnode), KM_SLEEP);
return ret;
}
void
chfs_free_full_dnode(struct chfs_full_dnode *fd)
{
kmem_free(fd,(sizeof(struct chfs_full_dnode)));
}
struct chfs_flash_vnode*
chfs_alloc_flash_vnode()
{
struct chfs_flash_vnode *ret;
ret = pool_cache_get(chfs_flash_vnode_cache, 0);
return ret;
}
void
chfs_free_flash_vnode(struct chfs_flash_vnode *fvnode)
{
pool_cache_put(chfs_flash_vnode_cache, fvnode);
}
struct chfs_flash_dirent_node*
chfs_alloc_flash_dirent()
{
struct chfs_flash_dirent_node *ret;
ret = pool_cache_get(chfs_flash_dirent_cache, 0);
return ret;
}
void
chfs_free_flash_dirent(struct chfs_flash_dirent_node *fdnode)
{
pool_cache_put(chfs_flash_dirent_cache, fdnode);
}
struct chfs_flash_data_node*
chfs_alloc_flash_dnode()
{
struct chfs_flash_data_node *ret;
ret = pool_cache_get(chfs_flash_dnode_cache, 0);
return ret;
}
void
chfs_free_flash_dnode(struct chfs_flash_data_node *fdnode)
{
pool_cache_put(chfs_flash_dnode_cache, fdnode);
}
struct chfs_node_frag*
chfs_alloc_node_frag()
{
struct chfs_node_frag *ret;
ret = pool_cache_get(chfs_node_frag_cache, 0);
return ret;
}
void
chfs_free_node_frag(struct chfs_node_frag *frag)
{
pool_cache_put(chfs_node_frag_cache, frag);
}
struct chfs_tmp_dnode *
chfs_alloc_tmp_dnode()
{
struct chfs_tmp_dnode *ret;
ret = pool_cache_get(chfs_tmp_dnode_cache, 0);
ret->next = NULL;
return ret;
}
void
chfs_free_tmp_dnode(struct chfs_tmp_dnode *td)
{
pool_cache_put(chfs_tmp_dnode_cache, td);
}
struct chfs_tmp_dnode_info *
chfs_alloc_tmp_dnode_info()
{
struct chfs_tmp_dnode_info *ret;
ret = pool_cache_get(chfs_tmp_dnode_info_cache, 0);
ret->tmpnode = NULL;
return ret;
}
void
chfs_free_tmp_dnode_info(struct chfs_tmp_dnode_info *di)
{
pool_cache_put(chfs_tmp_dnode_info_cache, di);
}

570
sys/ufs/chfs/chfs_nodeops.c Normal file
View File

@ -0,0 +1,570 @@
/* $NetBSD: chfs_nodeops.c,v 1.1 2011/11/24 15:51:31 ahoka Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
* University of Szeged, Hungary
* Copyright (C) 2010 David Tengeri <dtengeri@inf.u-szeged.hu>
* Copyright (C) 2010 Tamas Toth <ttoth@inf.u-szeged.hu>
* Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* 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 "chfs.h"
/**
* chfs_update_eb_dirty - updates dirty and free space, first and
* last node references
* @sbi: CHFS main descriptor structure
* @cheb: eraseblock to update
* @size: increase dirty space size with this
* Returns zero in case of success, %1 in case of fail.
*/
int
chfs_update_eb_dirty(struct chfs_mount *chmp,
struct chfs_eraseblock *cheb, uint32_t size)
{
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
KASSERT(!mutex_owned(&chmp->chm_lock_sizes));
if (!size)
return 0;
if (size > cheb->free_size) {
chfs_err("free_size (%d) is less then dirty space (%d) "
"on block (%d)\n", cheb->free_size, size, cheb->lnr);
return 1;
}
mutex_enter(&chmp->chm_lock_sizes);
//dbg("BEFORE: free_size: %d\n", cheb->free_size);
chfs_change_size_free(chmp, cheb, -size);
chfs_change_size_dirty(chmp, cheb, size);
//dbg(" AFTER: free_size: %d\n", cheb->free_size);
mutex_exit(&chmp->chm_lock_sizes);
return 0;
}
/**
* chfs_add_node_to_list - adds a data node ref to vnode cache's dnode list
* @sbi: super block informations
* @new: node ref to insert
* @list: head of the list
* This function inserts a data node ref to the list of vnode cache.
* The list is sorted by data node's lnr and offset.
*/
void
chfs_add_node_to_list(struct chfs_mount *chmp,
struct chfs_vnode_cache *vc,
struct chfs_node_ref *new, struct chfs_node_ref **list)
{
struct chfs_node_ref *nextref = *list;
struct chfs_node_ref *prevref = NULL;
while (nextref && nextref != (struct chfs_node_ref *)vc &&
(nextref->nref_lnr <= new->nref_lnr)) {
if (nextref->nref_lnr == new->nref_lnr) {
while (nextref && nextref !=
(struct chfs_node_ref *)vc &&
(CHFS_GET_OFS(nextref->nref_offset) <
CHFS_GET_OFS(new->nref_offset))) {
prevref = nextref;
nextref = nextref->nref_next;
}
break;
}
prevref = nextref;
nextref = nextref->nref_next;
}
if (nextref && nextref != (struct chfs_node_ref *)vc &&
nextref->nref_lnr == new->nref_lnr &&
CHFS_GET_OFS(nextref->nref_offset) ==
CHFS_GET_OFS(new->nref_offset)) {
new->nref_next = nextref->nref_next;
} else {
new->nref_next = nextref;
}
if (prevref) {
prevref->nref_next = new;
} else {
*list = new;
}
}
void
chfs_add_fd_to_inode(struct chfs_mount *chmp,
struct chfs_inode *parent, struct chfs_dirent *new)
{
// struct chfs_dirent **prev = &parent->dents;
struct chfs_dirent *fd, *tmpfd;
if (new->version > parent->chvc->highest_version) {
parent->chvc->highest_version = new->version;
}
//mutex_enter(&parent->inode_lock);
TAILQ_FOREACH_SAFE(fd, &parent->dents, fds, tmpfd) {
if (fd->nhash > new->nhash) {
/* insert new before fd */
TAILQ_INSERT_BEFORE(fd, new, fds);
return;
} else if (fd->nhash == new->nhash &&
!strcmp(fd->name, new->name)) {
if (new->version > fd->version) {
// new->next = fd->next;
/* replace fd with new */
TAILQ_INSERT_BEFORE(fd, new, fds);
TAILQ_REMOVE(&parent->dents, fd, fds);
if (fd->nref) {
chfs_mark_node_obsolete(chmp,
fd->nref);
}
chfs_free_dirent(fd);
// *prev = new;//XXX
} else {
chfs_mark_node_obsolete(chmp, new->nref);
chfs_free_dirent(new);
}
return;
}
}
/* if we couldnt fit it elsewhere, lets add to the end */
/* FIXME insert tail or insert head? */
TAILQ_INSERT_HEAD(&parent->dents, new, fds);
//mutex_exit(&parent->inode_lock);
#if 0
while ((*prev) && (*prev)->nhash <= new->nhash) {
if ((*prev)->nhash == new->nhash &&
!strcmp((*prev)->name, new->name)) {
if (new->version > (*prev)->version) {
new->next = (*prev)->next;
if ((*prev)->nref) {
chfs_mark_node_obsolete(chmp,
(*prev)->nref);
}
chfs_free_dirent(*prev);
*prev = new;
} else {
chfs_mark_node_obsolete(chmp, new->nref);
chfs_free_dirent(new);
}
return;
}
prev = &((*prev)->next);
}
new->next = *prev;
*prev = new;
#endif
}
void
chfs_add_vnode_ref_to_vc(struct chfs_mount *chmp,
struct chfs_vnode_cache *vc, struct chfs_node_ref *new)
{
if ((struct chfs_vnode_cache*)(vc->v) != vc) {
chfs_mark_node_obsolete(chmp, vc->v);
new->nref_next = vc->v->nref_next;
} else {
new->nref_next = vc->v;
}
vc->v = new;
}
struct chfs_node_ref *
chfs_nref_next(struct chfs_node_ref *nref)
{
// dbg("check nref: %u - %u\n", nref->nref_lnr, nref->nref_offset);
nref++;
// dbg("next nref: %u - %u\n", nref->nref_lnr, nref->nref_offset);
if (nref->nref_lnr == REF_LINK_TO_NEXT) {
//End of chain
if (!nref->nref_next)
return NULL;
nref = nref->nref_next;
}
//end of chain
if (nref->nref_lnr == REF_EMPTY_NODE)
return NULL;
return nref;
}
int
chfs_nref_len(struct chfs_mount *chmp,
struct chfs_eraseblock *cheb, struct chfs_node_ref *nref)
{
struct chfs_node_ref *next;
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
if (!cheb)
cheb = &chmp->chm_blocks[nref->nref_lnr];
next = chfs_nref_next(nref);
if (!next) {
//dbg("next null\n");
return chmp->chm_ebh->eb_size - cheb->free_size -
CHFS_GET_OFS(nref->nref_offset);
}
//dbg("size: %d\n", CHFS_GET_OFS(next->nref_offset) - CHFS_GET_OFS(nref->nref_offset));
return CHFS_GET_OFS(next->nref_offset) -
CHFS_GET_OFS(nref->nref_offset);
}
/**
* chfs_mark_node_obsolete - marks a node obsolete
*/
void
chfs_mark_node_obsolete(struct chfs_mount *chmp,
struct chfs_node_ref *nref)
{
int len;
struct chfs_eraseblock *cheb;
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
KASSERT(!CHFS_REF_OBSOLETE(nref));
KASSERT(nref->nref_lnr <= chmp->chm_ebh->peb_nr);
cheb = &chmp->chm_blocks[nref->nref_lnr];
#ifdef DIAGNOSTIC
if (cheb->used_size + cheb->free_size + cheb->dirty_size +
cheb->unchecked_size + cheb->wasted_size != chmp->chm_ebh->eb_size) {
dbg("eraseblock leak detected!\nused: %u\nfree: %u\n"
"dirty: %u\nunchecked: %u\nwasted: %u\ntotal: %u\nshould be: %zu\n",
cheb->used_size, cheb->free_size, cheb->dirty_size,
cheb->unchecked_size, cheb->wasted_size, cheb->used_size + cheb->free_size +
cheb->dirty_size + cheb->unchecked_size + cheb->wasted_size,
chmp->chm_ebh->eb_size);
}
#endif
len = chfs_nref_len(chmp, cheb, nref);
//dbg("len: %u\n", len);
//dbg("1. used: %u\n", cheb->used_size);
mutex_enter(&chmp->chm_lock_sizes);
if (CHFS_REF_FLAGS(nref) == CHFS_UNCHECKED_NODE_MASK) {
//dbg("UNCHECKED mark an unchecked node\n");
chfs_change_size_unchecked(chmp, cheb, -len);
//dbg("unchecked: %u\n", chmp->chm_unchecked_size);
} else {
chfs_change_size_used(chmp, cheb, -len);
//dbg("2. used: %u\n", cheb->used_size);
KASSERT(cheb->used_size <= chmp->chm_ebh->eb_size);
}
chfs_change_size_dirty(chmp, cheb, len);
#ifdef DIAGNOSTIC
if (cheb->used_size + cheb->free_size + cheb->dirty_size +
cheb->unchecked_size + cheb->wasted_size != chmp->chm_ebh->eb_size) {
panic("eraseblock leak detected!\nused: %u\nfree: %u\n"
"dirty: %u\nunchecked: %u\nwasted: %u\ntotal: %u\nshould be: %zu\n",
cheb->used_size, cheb->free_size, cheb->dirty_size,
cheb->unchecked_size, cheb->wasted_size, cheb->used_size + cheb->free_size +
cheb->dirty_size + cheb->unchecked_size + cheb->wasted_size,
chmp->chm_ebh->eb_size);
}
#endif
nref->nref_offset = CHFS_GET_OFS(nref->nref_offset) |
CHFS_OBSOLETE_NODE_MASK;
if (chmp->chm_flags & CHFS_MP_FLAG_SCANNING) {
/*Scan is in progress, do nothing now*/
mutex_exit(&chmp->chm_lock_sizes);
return;
}
if (cheb == chmp->chm_nextblock) {
dbg("Not moving nextblock to dirty/erase_pending list\n");
} else if (!cheb->used_size && !cheb->unchecked_size) {
if (cheb == chmp->chm_gcblock) {
dbg("gcblock is completely dirtied\n");
chmp->chm_gcblock = NULL;
} else {
//remove from a tailq, but we don't know which tailq contains this cheb
//so we remove it from the dirty list now
//TAILQ_REMOVE(&chmp->chm_dirty_queue, cheb, queue);
int removed = 0;
struct chfs_eraseblock *eb, *tmpeb;
//XXX ugly code
TAILQ_FOREACH_SAFE(eb, &chmp->chm_free_queue, queue, tmpeb) {
if (eb == cheb) {
TAILQ_REMOVE(&chmp->chm_free_queue, cheb, queue);
removed = 1;
break;
}
}
if (removed == 0) {
TAILQ_FOREACH_SAFE(eb, &chmp->chm_dirty_queue, queue, tmpeb) {
if (eb == cheb) {
TAILQ_REMOVE(&chmp->chm_dirty_queue, cheb, queue);
removed = 1;
break;
}
}
}
if (removed == 0) {
TAILQ_FOREACH_SAFE(eb, &chmp->chm_very_dirty_queue, queue, tmpeb) {
if (eb == cheb) {
TAILQ_REMOVE(&chmp->chm_very_dirty_queue, cheb, queue);
removed = 1;
break;
}
}
}
if (removed == 0) {
TAILQ_FOREACH_SAFE(eb, &chmp->chm_clean_queue, queue, tmpeb) {
if (eb == cheb) {
TAILQ_REMOVE(&chmp->chm_clean_queue, cheb, queue);
removed = 1;
break;
}
}
}
}
if (chmp->chm_wbuf_len) {
dbg("Adding block to erasable pending wbuf queue\n");
TAILQ_INSERT_TAIL(&chmp->chm_erasable_pending_wbuf_queue,
cheb, queue);
} else {
TAILQ_INSERT_TAIL(&chmp->chm_erase_pending_queue,
cheb, queue);
chmp->chm_nr_erasable_blocks++;
}
chfs_remap_leb(chmp);
} else if (cheb == chmp->chm_gcblock) {
dbg("Not moving gcblock to dirty list\n");
} else if (cheb->dirty_size > MAX_DIRTY_TO_CLEAN &&
cheb->dirty_size - len <= MAX_DIRTY_TO_CLEAN) {
dbg("Freshly dirtied, remove it from clean queue and "
"add it to dirty\n");
TAILQ_REMOVE(&chmp->chm_clean_queue, cheb, queue);
TAILQ_INSERT_TAIL(&chmp->chm_dirty_queue, cheb, queue);
} else if (VERY_DIRTY(chmp, cheb->dirty_size) &&
!VERY_DIRTY(chmp, cheb->dirty_size - len)) {
dbg("Becomes now very dirty, remove it from dirty "
"queue and add it to very dirty\n");
TAILQ_REMOVE(&chmp->chm_dirty_queue, cheb, queue);
TAILQ_INSERT_TAIL(&chmp->chm_very_dirty_queue, cheb, queue);
} else {
dbg("Leave cheb where it is\n");
}
mutex_exit(&chmp->chm_lock_sizes);
return;
}
/**
* chfs_close_eraseblock - close an eraseblock
* @chmp: chfs mount structure
* @cheb: eraseblock informations
*
* This function close the physical chain of the nodes on the eraseblock,
* convert its free size to dirty and add it to clean, dirty or very dirty list.
*/
int
chfs_close_eraseblock(struct chfs_mount *chmp,
struct chfs_eraseblock *cheb)
{
uint32_t offset;
struct chfs_node_ref *nref;
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
offset = chmp->chm_ebh->eb_size - cheb->free_size;
// Close the chain
nref = chfs_alloc_node_ref(cheb);
if (!nref)
return ENOMEM;
nref->nref_next = NULL;
nref->nref_offset = offset;
// Mark space as dirty
chfs_update_eb_dirty(chmp, cheb, cheb->free_size);
if (cheb->dirty_size < MAX_DIRTY_TO_CLEAN) {
TAILQ_INSERT_TAIL(&chmp->chm_clean_queue, cheb, queue);
} else if (VERY_DIRTY(chmp, cheb->dirty_size)) {
TAILQ_INSERT_TAIL(&chmp->chm_very_dirty_queue, cheb, queue);
} else {
TAILQ_INSERT_TAIL(&chmp->chm_dirty_queue, cheb, queue);
}
return 0;
}
int
chfs_reserve_space_normal(struct chfs_mount *chmp, uint32_t size, int prio)
{
int ret;
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
mutex_enter(&chmp->chm_lock_sizes);
while (chmp->chm_nr_free_blocks + chmp->chm_nr_erasable_blocks < chmp->chm_resv_blocks_write) {
dbg("free: %d, erasable: %d, resv: %d\n", chmp->chm_nr_free_blocks, chmp->chm_nr_erasable_blocks, chmp->chm_resv_blocks_write);
uint32_t avail, dirty;
if (prio == ALLOC_DELETION && chmp->chm_nr_free_blocks + chmp->chm_nr_erasable_blocks >= chmp->chm_resv_blocks_deletion)
break;
dirty = chmp->chm_dirty_size - chmp->chm_nr_erasable_blocks * chmp->chm_ebh->eb_size + chmp->chm_unchecked_size;
if (dirty < chmp->chm_nospc_dirty) {
dbg("dirty: %u < nospc_dirty: %u\n", dirty, chmp->chm_nospc_dirty);
ret = ENOSPC;
mutex_exit(&chmp->chm_lock_sizes);
goto out;
}
avail = chmp->chm_free_size - (chmp->chm_resv_blocks_write * chmp->chm_ebh->eb_size);
if (size > avail) {
dbg("size: %u > avail: %u\n", size, avail);
ret = ENOSPC;
mutex_exit(&chmp->chm_lock_sizes);
goto out;
}
mutex_exit(&chmp->chm_lock_sizes);
ret = chfs_gcollect_pass(chmp);
/* gcollect_pass exits chm_lock_mountfields */
mutex_enter(&chmp->chm_lock_mountfields);
mutex_enter(&chmp->chm_lock_sizes);
if (chmp->chm_nr_erasable_blocks ||
!TAILQ_EMPTY(&chmp->chm_erasable_pending_wbuf_queue) ||
ret == EAGAIN) {
ret = chfs_remap_leb(chmp);
}
if (ret) {
mutex_exit(&chmp->chm_lock_sizes);
goto out;
}
}
mutex_exit(&chmp->chm_lock_sizes);
ret = chfs_reserve_space(chmp, size);
out:
return ret;
}
int
chfs_reserve_space_gc(struct chfs_mount *chmp, uint32_t size)
{
int ret;
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
mutex_enter(&chmp->chm_lock_sizes);
chfs_remap_leb(chmp);
if (size > chmp->chm_free_size) {
dbg("size: %u\n", size);
mutex_exit(&chmp->chm_lock_sizes);
return ENOSPC;
}
mutex_exit(&chmp->chm_lock_sizes);
ret = chfs_reserve_space(chmp, size);
return ret;
}
/**
* chfs_reserve_space - finds a block which free size is >= requested size
* @chmp: chfs mount point
* @size: requested size
* @len: reserved spaced will be returned in this variable;
* Returns zero in case of success, error code in case of fail.
*/
int
chfs_reserve_space(struct chfs_mount *chmp, uint32_t size)
{
//TODO define minimum reserved blocks, which is needed for writing
//TODO check we have enough free blocks to write
//TODO if no: need erase and GC
int err;
struct chfs_eraseblock *cheb;
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
KASSERT(!mutex_owned(&chmp->chm_lock_sizes));
cheb = chmp->chm_nextblock;
//if (cheb)
//dbg("cheb->free_size %u\n", cheb->free_size);
if (cheb && size > cheb->free_size) {
dbg("size: %u > free_size: %u\n", size, cheb->free_size);
/*
* There isn't enough space on this eraseblock, we mark this as
* dirty and close the physical chain of the node refs.
*/
//Write out pending data if any
if (chmp->chm_wbuf_len) {
chfs_flush_pending_wbuf(chmp);
//FIXME need goto restart here?
}
while (chmp->chm_wbuf_ofs < chmp->chm_ebh->eb_size) {
dbg("wbuf ofs: %zu - eb_size: %zu\n",
chmp->chm_wbuf_ofs, chmp->chm_ebh->eb_size);
chfs_flush_pending_wbuf(chmp);
}
if (!(chmp->chm_wbuf_ofs % chmp->chm_ebh->eb_size) && !chmp->chm_wbuf_len)
chmp->chm_wbuf_ofs = 0xffffffff;
err = chfs_close_eraseblock(chmp, cheb);
if (err)
return err;
cheb = NULL;
}
if (!cheb) {
//get a block for nextblock
if (TAILQ_EMPTY(&chmp->chm_free_queue)) {
// If this succeeds there will be a block on free_queue
dbg("cheb remap (free: %d)\n", chmp->chm_nr_free_blocks);
err = chfs_remap_leb(chmp);
if (err)
return err;
}
cheb = TAILQ_FIRST(&chmp->chm_free_queue);
TAILQ_REMOVE(&chmp->chm_free_queue, cheb, queue);
chmp->chm_nextblock = cheb;
chmp->chm_nr_free_blocks--;
}
return 0;
}

211
sys/ufs/chfs/chfs_pool.c Normal file
View File

@ -0,0 +1,211 @@
/* $NetBSD: chfs_pool.c,v 1.1 2011/11/24 15:51:31 ahoka Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
* University of Szeged, Hungary
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* 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.
*/
/*
* Pool allocator and convenience routines for chfs.
*/
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/pool.h>
#include <sys/atomic.h>
#include <uvm/uvm.h>
#include "chfs.h"
//#include </root/xipffs/netbsd.chfs/chfs.h>
/* --------------------------------------------------------------------- */
void * chfs_pool_page_alloc(struct pool *, int);
void chfs_pool_page_free(struct pool *, void *);
extern void* pool_page_alloc_nointr(struct pool *, int);
extern void pool_page_free_nointr(struct pool *, void *);
/* --------------------------------------------------------------------- */
struct pool_allocator chfs_pool_allocator = {
.pa_alloc = chfs_pool_page_alloc,
.pa_free = chfs_pool_page_free,
};
/* --------------------------------------------------------------------- */
void
chfs_pool_init(struct chfs_pool *chpp, size_t size, const char *what,
struct chfs_mount *chmp)
{
int cnt;
cnt = snprintf(chpp->chp_name, sizeof(chpp->chp_name),
"%s_chfs_%p", what, chmp);
KASSERT(cnt < sizeof(chpp->chp_name));
pool_init(&chpp->chp_pool, size, 0, 0, 0, chpp->chp_name,
&chfs_pool_allocator, IPL_NONE);
chpp->chp_mount = chmp;
}
/* --------------------------------------------------------------------- */
void
chfs_pool_destroy(struct chfs_pool *chpp)
{
pool_destroy((struct pool *)chpp);
}
/* --------------------------------------------------------------------- */
void *
chfs_pool_page_alloc(struct pool *pp, int flags)
{
struct chfs_pool *chpp;
struct chfs_mount *chmp;
unsigned int pages;
void *page;
dbg("CHFS: pool_page_alloc()\n");
chpp = (struct chfs_pool *)pp;
chmp = chpp->chp_mount;
pages = atomic_inc_uint_nv(&chmp->chm_pages_used);
if (pages >= CHFS_PAGES_MAX(chmp)) {
atomic_dec_uint(&chmp->chm_pages_used);
return NULL;
}
page = pool_page_alloc_nointr(pp, flags | PR_WAITOK);
if (page == NULL) {
atomic_dec_uint(&chmp->chm_pages_used);
}
return page;
}
/* --------------------------------------------------------------------- */
void
chfs_pool_page_free(struct pool *pp, void *v)
{
struct chfs_pool *chpp;
struct chfs_mount *chmp;
dbg("CHFS: pool_page_free()\n");
chpp = (struct chfs_pool *)pp;
chmp = chpp->chp_mount;
atomic_dec_uint(&chmp->chm_pages_used);
pool_page_free_nointr(pp, v);
}
/* --------------------------------------------------------------------- */
void
chfs_str_pool_init(struct chfs_str_pool *chsp, struct chfs_mount *chmp)
{
dbg("CHFS: str_pool_init()\n");
chfs_pool_init(&chsp->chsp_pool_16, 16, "str", chmp);
chfs_pool_init(&chsp->chsp_pool_32, 32, "str", chmp);
chfs_pool_init(&chsp->chsp_pool_64, 64, "str", chmp);
chfs_pool_init(&chsp->chsp_pool_128, 128, "str", chmp);
chfs_pool_init(&chsp->chsp_pool_256, 256, "str", chmp);
chfs_pool_init(&chsp->chsp_pool_512, 512, "str", chmp);
chfs_pool_init(&chsp->chsp_pool_1024, 1024, "str", chmp);
}
/* --------------------------------------------------------------------- */
void
chfs_str_pool_destroy(struct chfs_str_pool *chsp)
{
dbg("CHFS: str_pool_destroy()\n");
chfs_pool_destroy(&chsp->chsp_pool_16);
chfs_pool_destroy(&chsp->chsp_pool_32);
chfs_pool_destroy(&chsp->chsp_pool_64);
chfs_pool_destroy(&chsp->chsp_pool_128);
chfs_pool_destroy(&chsp->chsp_pool_256);
chfs_pool_destroy(&chsp->chsp_pool_512);
chfs_pool_destroy(&chsp->chsp_pool_1024);
}
/* --------------------------------------------------------------------- */
char *
chfs_str_pool_get(struct chfs_str_pool *chsp, size_t len, int flags)
{
struct chfs_pool *p;
dbg("CHFS: str_pool_get()\n");
KASSERT(len <= 1024);
if (len <= 16) p = &chsp->chsp_pool_16;
else if (len <= 32) p = &chsp->chsp_pool_32;
else if (len <= 64) p = &chsp->chsp_pool_64;
else if (len <= 128) p = &chsp->chsp_pool_128;
else if (len <= 256) p = &chsp->chsp_pool_256;
else if (len <= 512) p = &chsp->chsp_pool_512;
else if (len <= 1024) p = &chsp->chsp_pool_1024;
else {
KASSERT(0);
p = NULL; /* Silence compiler warnings */
}
return (char *)CHFS_POOL_GET(p, flags);
}
/* --------------------------------------------------------------------- */
void
chfs_str_pool_put(struct chfs_str_pool *chsp, char *str, size_t len)
{
struct chfs_pool *p;
dbg("CHFS: str_pool_put()\n");
KASSERT(len <= 1024);
if (len <= 16) p = &chsp->chsp_pool_16;
else if (len <= 32) p = &chsp->chsp_pool_32;
else if (len <= 64) p = &chsp->chsp_pool_64;
else if (len <= 128) p = &chsp->chsp_pool_128;
else if (len <= 256) p = &chsp->chsp_pool_256;
else if (len <= 512) p = &chsp->chsp_pool_512;
else if (len <= 1024) p = &chsp->chsp_pool_1024;
else {
KASSERT(0);
p = NULL; /* Silence compiler warnings */
}
CHFS_POOL_PUT(p, str);
}

84
sys/ufs/chfs/chfs_pool.h Normal file
View File

@ -0,0 +1,84 @@
/* $NetBSD: chfs_pool.h,v 1.1 2011/11/24 15:51:31 ahoka Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
* University of Szeged, Hungary
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* 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.
*/
#ifndef _FS_CHFS_CHFS_POOL_H_
#define _FS_CHFS_CHFS_POOL_H_
/* --------------------------------------------------------------------- */
struct chfs_pool {
struct pool chp_pool;
struct chfs_mount * chp_mount;
char chp_name[64];
};
/* --------------------------------------------------------------------- */
struct chfs_str_pool {
struct chfs_pool chsp_pool_16;
struct chfs_pool chsp_pool_32;
struct chfs_pool chsp_pool_64;
struct chfs_pool chsp_pool_128;
struct chfs_pool chsp_pool_256;
struct chfs_pool chsp_pool_512;
struct chfs_pool chsp_pool_1024;
};
/* --------------------------------------------------------------------- */
#ifdef _KERNEL
/*
* Convenience functions and macros to manipulate a chfs_pool.
*/
void chfs_pool_init(struct chfs_pool *chpp, size_t size,
const char *what, struct chfs_mount *chmp);
void chfs_pool_destroy(struct chfs_pool *chpp);
#define CHFS_POOL_GET(chpp, flags) pool_get((struct pool *)(chpp), flags)
#define CHFS_POOL_PUT(chpp, v) pool_put((struct pool *)(chpp), v)
/* --------------------------------------------------------------------- */
/*
* Functions to manipulate a chfs_str_pool.
*/
void chfs_str_pool_init(struct chfs_str_pool *, struct chfs_mount *);
void chfs_str_pool_destroy(struct chfs_str_pool *);
char * chfs_str_pool_get(struct chfs_str_pool *, size_t, int);
void chfs_str_pool_put(struct chfs_str_pool *, char *, size_t);
#endif
#endif /* _FS_CHFS_CHFS_POOL_H_ */

File diff suppressed because it is too large Load Diff

740
sys/ufs/chfs/chfs_scan.c Normal file
View File

@ -0,0 +1,740 @@
/* $NetBSD: chfs_scan.c,v 1.1 2011/11/24 15:51:31 ahoka Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
* University of Szeged, Hungary
* Copyright (c) 2010 David Tengeri <dtengeri@inf.u-szeged.hu>
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* 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.
*/
/*
* chfs_scan.c
*
* Created on: 2009.11.05.
* Author: dtengeri
*/
#include "chfs.h"
/**
* chfs_scan_make_vnode_cache - makes a new vnode cache during scan
* @chmp: CHFS main descriptor structure
* @vno: vnode identifier
* This function returns a vnode cache belonging to @vno.
*/
struct chfs_vnode_cache *
chfs_scan_make_vnode_cache(struct chfs_mount *chmp, ino_t vno)
{
struct chfs_vnode_cache *vc;
KASSERT(mutex_owned(&chmp->chm_lock_vnocache));
vc = chfs_vnode_cache_get(chmp, vno);
if (vc) {
return vc;
}
if (vno > chmp->chm_max_vno) {
chmp->chm_max_vno = vno;
}
vc = chfs_vnode_cache_alloc(vno);
//mutex_enter(&chmp->chm_lock_vnocache);
chfs_vnode_cache_add(chmp, vc);
//mutex_exit(&chmp->chm_lock_vnocache);
if (vno == CHFS_ROOTINO) {
vc->nlink = 2;
vc->pvno = CHFS_ROOTINO;
chfs_vnode_cache_set_state(chmp,
vc, VNO_STATE_CHECKEDABSENT);
}
return vc;
}
/**
* chfs_scan_check_node_hdr - checks node magic and crc
* @nhdr: node header to check
* Returns 0 if everything is OK, error code otherwise.
*/
int
chfs_scan_check_node_hdr(struct chfs_flash_node_hdr *nhdr)
{
uint16_t magic;
uint32_t crc, hdr_crc;
magic = le16toh(nhdr->magic);
if (magic != CHFS_FS_MAGIC_BITMASK) {
dbg("bad magic\n");
return CHFS_NODE_BADMAGIC;
}
hdr_crc = le32toh(nhdr->hdr_crc);
crc = crc32(0, (uint8_t *)nhdr, CHFS_NODE_HDR_SIZE - 4);
if (crc != hdr_crc) {
dbg("bad crc\n");
return CHFS_NODE_BADCRC;
}
return CHFS_NODE_OK;
}
/**
* chfs_scan_check_vnode - check vnode crc and add to vnode cache
* @chmp: CHFS main descriptor structure
* @cheb: eraseblock informations
* @buf: vnode to check
* @ofs: offset in eraseblock where vnode starts
*/
int
chfs_scan_check_vnode(struct chfs_mount *chmp,
struct chfs_eraseblock *cheb, void *buf, off_t ofs)
{
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
struct chfs_vnode_cache *vc;
struct chfs_flash_vnode *vnode = buf;
struct chfs_node_ref *nref;
int err;
uint32_t crc;
ino_t vno;
crc = crc32(0, (uint8_t *)vnode,
sizeof(struct chfs_flash_vnode) - 4);
if (crc != le32toh(vnode->node_crc)) {
err = chfs_update_eb_dirty(chmp,
cheb, le32toh(vnode->length));
if (err) {
return err;
}
return CHFS_NODE_BADCRC;
}
vno = le64toh(vnode->vno);
mutex_enter(&chmp->chm_lock_vnocache);
vc = chfs_vnode_cache_get(chmp, vno);
if (!vc) {
vc = chfs_scan_make_vnode_cache(chmp, vno);
if (!vc) {
mutex_exit(&chmp->chm_lock_vnocache);
return ENOMEM;
}
}
mutex_exit(&chmp->chm_lock_vnocache);
nref = chfs_alloc_node_ref(cheb);
nref->nref_offset = ofs;
KASSERT(nref->nref_lnr == cheb->lnr);
/* Check version of vnode. */
if ((struct chfs_vnode_cache *)vc->v != vc) {
if (le64toh(vnode->version) > *vc->vno_version) {
//err = chfs_update_eb_dirty(chmp, &chmp->chm_blocks[vc->v->lnr],
// sizeof(struct chfs_flash_vnode));
*vc->vno_version = le64toh(vnode->version);
chfs_add_vnode_ref_to_vc(chmp, vc, nref);
} else {
err = chfs_update_eb_dirty(chmp, cheb,
sizeof(struct chfs_flash_vnode));
return CHFS_NODE_OK;
}
} else {
vc->vno_version = kmem_alloc(sizeof(uint64_t), KM_SLEEP);
if (!vc->vno_version)
return ENOMEM;
*vc->vno_version = le64toh(vnode->version);
chfs_add_vnode_ref_to_vc(chmp, vc, nref);
}
mutex_enter(&chmp->chm_lock_sizes);
//dbg("B:lnr: %d |free_size: %d node's size: %d\n", cheb->lnr, cheb->free_size, le32toh(vnode->length));
chfs_change_size_free(chmp, cheb, -le32toh(vnode->length));
chfs_change_size_used(chmp, cheb, le32toh(vnode->length));
mutex_exit(&chmp->chm_lock_sizes);
KASSERT(cheb->used_size <= chmp->chm_ebh->eb_size);
KASSERT(cheb->used_size + cheb->free_size + cheb->dirty_size + cheb->unchecked_size + cheb->wasted_size == chmp->chm_ebh->eb_size);
//dbg(" A: free_size: %d\n", cheb->free_size);
/*dbg("vnode dump:\n");
dbg(" ->magic: 0x%x\n", le16toh(vnode->magic));
dbg(" ->type: %d\n", le16toh(vnode->type));
dbg(" ->length: %d\n", le32toh(vnode->length));
dbg(" ->hdr_crc: 0x%x\n", le32toh(vnode->hdr_crc));
dbg(" ->vno: %d\n", le64toh(vnode->vno));
dbg(" ->version: %ld\n", le64toh(vnode->version));
dbg(" ->uid: %d\n", le16toh(vnode->uid));
dbg(" ->gid: %d\n", le16toh(vnode->gid));
dbg(" ->mode: %d\n", le32toh(vnode->mode));
dbg(" ->dn_size: %d\n", le32toh(vnode->dn_size));
dbg(" ->atime: %d\n", le32toh(vnode->atime));
dbg(" ->mtime: %d\n", le32toh(vnode->mtime));
dbg(" ->ctime: %d\n", le32toh(vnode->ctime));
dbg(" ->dsize: %d\n", le32toh(vnode->dsize));
dbg(" ->node_crc: 0x%x\n", le32toh(vnode->node_crc));*/
return CHFS_NODE_OK;
}
int
chfs_scan_mark_dirent_obsolete(struct chfs_mount *chmp,
struct chfs_vnode_cache *vc, struct chfs_dirent *fd)
{
//int size;
struct chfs_eraseblock *cheb;
struct chfs_node_ref *prev, *nref;
nref = fd->nref;
cheb = &chmp->chm_blocks[fd->nref->nref_lnr];
/* Remove dirent's node ref from vnode cache */
prev = vc->dirents;
if (prev && prev == nref) {
vc->dirents = prev->nref_next;
} else if (prev && prev != (void *)vc) {
while (prev->nref_next && prev->nref_next !=
(void *)vc && prev->nref_next != nref) {
prev = prev->nref_next;
}
if (prev->nref_next == nref) {
prev->nref_next = nref->nref_next;
}
}
/*dbg("XXX - start\n");
//nref = vc->dirents;
struct chfs_dirent *tmp;
tmp = vc->scan_dirents;
while (tmp) {
dbg(" ->tmp->name: %s\n", tmp->name);
dbg(" ->tmp->version: %ld\n", tmp->version);
dbg(" ->tmp->vno: %d\n", tmp->vno);
tmp = tmp->next;
}
dbg("XXX - end\n");*/
//size = CHFS_PAD(sizeof(struct chfs_flash_dirent_node) + fd->nsize);
KASSERT(cheb->used_size + cheb->free_size + cheb->dirty_size +
cheb->unchecked_size + cheb->wasted_size == chmp->chm_ebh->eb_size);
return 0;
}
void
chfs_add_fd_to_list(struct chfs_mount *chmp,
struct chfs_dirent *new, struct chfs_vnode_cache *pvc)
{
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
int size;
struct chfs_eraseblock *cheb, *oldcheb;
// struct chfs_dirent **prev;
struct chfs_dirent *fd, *tmpfd;
dbg("adding fd to list: %s\n", new->name);
if ((new->version > pvc->highest_version))
pvc->highest_version = new->version;
size = CHFS_PAD(sizeof(struct chfs_flash_dirent_node) +
new->nsize);
cheb = &chmp->chm_blocks[new->nref->nref_lnr];
mutex_enter(&chmp->chm_lock_sizes);
TAILQ_FOREACH_SAFE(fd, &pvc->scan_dirents, fds, tmpfd) {
if (fd->nhash > new->nhash) {
/* insert new before fd */
TAILQ_INSERT_BEFORE(fd, new, fds);
goto out;
} else if (fd->nhash == new->nhash &&
!strcmp(fd->name, new->name)) {
if (new->version > fd->version) {
// new->next = fd->next;
/* replace fd with new */
TAILQ_INSERT_BEFORE(fd, new, fds);
chfs_change_size_free(chmp, cheb, -size);
chfs_change_size_used(chmp, cheb, size);
TAILQ_REMOVE(&pvc->scan_dirents, fd, fds);
if (fd->nref) {
size = CHFS_PAD(sizeof(struct chfs_flash_dirent_node) + fd->nsize);
chfs_scan_mark_dirent_obsolete(chmp, pvc, fd);
oldcheb = &chmp->chm_blocks[fd->nref->nref_lnr];
chfs_change_size_used(chmp, oldcheb, -size);
chfs_change_size_dirty(chmp, oldcheb, size);
}
chfs_free_dirent(fd);
// *prev = new;//XXX
} else {
chfs_scan_mark_dirent_obsolete(chmp, pvc, new);
chfs_change_size_free(chmp, cheb, -size);
chfs_change_size_dirty(chmp, cheb, size);
chfs_free_dirent(new);
}
/*dbg("START\n");
fd = pvc->scan_dirents;
while (fd) {
dbg("dirent dump:\n");
dbg(" ->vno: %d\n", fd->vno);
dbg(" ->version: %ld\n", fd->version);
dbg(" ->nhash: 0x%x\n", fd->nhash);
dbg(" ->nsize: %d\n", fd->nsize);
dbg(" ->name: %s\n", fd->name);
dbg(" ->type: %d\n", fd->type);
fd = fd->next;
}
dbg("END\n");*/
mutex_exit(&chmp->chm_lock_sizes);
return;
}
}
/* if we couldnt fit it elsewhere, lets add to the end */
TAILQ_INSERT_TAIL(&pvc->scan_dirents, new, fds);
out:
//dbg("B:lnr: %d |free_size: %d size: %d\n", cheb->lnr, cheb->free_size, size);
chfs_change_size_free(chmp, cheb, -size);
chfs_change_size_used(chmp, cheb, size);
mutex_exit(&chmp->chm_lock_sizes);
KASSERT(cheb->used_size <= chmp->chm_ebh->eb_size);
//dbg(" A: free_size: %d\n", cheb->free_size);
KASSERT(cheb->used_size + cheb->free_size + cheb->dirty_size + cheb->unchecked_size + cheb->wasted_size == chmp->chm_ebh->eb_size);
// fd = pvc->scan_dirents;
/*dbg("START\n");
while (fd) {
dbg("dirent dump:\n");
dbg(" ->vno: %d\n", fd->vno);
dbg(" ->version: %ld\n", fd->version);
dbg(" ->nhash: 0x%x\n", fd->nhash);
dbg(" ->nsize: %d\n", fd->nsize);
dbg(" ->name: %s\n", fd->name);
dbg(" ->type: %d\n", fd->type);
fd = fd->next;
}
dbg("END\n");*/
}
/**
* chfs_scan_check_dirent_node - check vnode crc and add to vnode cache
* @chmp: CHFS main descriptor structure
* @cheb: eraseblock informations
* @buf: directory entry to check
* @ofs: offset in eraseblock where dirent starts
*/
int
chfs_scan_check_dirent_node(struct chfs_mount *chmp,
struct chfs_eraseblock *cheb, void *buf, off_t ofs)
{
int err, namelen;
uint32_t crc;
struct chfs_dirent *fd;
struct chfs_vnode_cache *vc;
struct chfs_flash_dirent_node *dirent = buf;
//struct chfs_node_ref *tmp;
crc = crc32(0, (uint8_t *)dirent, sizeof(*dirent) - 4);
if (crc != le32toh(dirent->node_crc)) {
err = chfs_update_eb_dirty(chmp, cheb, le32toh(dirent->length));
if (err)
return err;
return CHFS_NODE_BADCRC;
}
namelen = dirent->nsize;
fd = chfs_alloc_dirent(namelen + 1);
if (!fd)
return ENOMEM;
fd->nref = chfs_alloc_node_ref(cheb);
if (!fd->nref)
return ENOMEM;
KASSERT(fd->nref->nref_lnr == cheb->lnr);
memcpy(&fd->name, dirent->name, namelen);
fd->nsize = namelen;
fd->name[namelen] = 0;
crc = crc32(0, fd->name, dirent->nsize);
if (crc != le32toh(dirent->name_crc)) {
chfs_err("Directory entry's name has bad crc: read: 0x%x, "
"calculated: 0x%x\n", le32toh(dirent->name_crc), crc);
chfs_free_dirent(fd);
err = chfs_update_eb_dirty(chmp, cheb, le32toh(dirent->length));
if (err)
return err;
return CHFS_NODE_BADNAMECRC;
}
/* Check vnode_cache of parent node */
mutex_enter(&chmp->chm_lock_vnocache);
vc = chfs_scan_make_vnode_cache(chmp, le64toh(dirent->pvno));
mutex_exit(&chmp->chm_lock_vnocache);
if (!vc) {
chfs_free_dirent(fd);
return ENOMEM;
}
fd->nref->nref_offset = ofs;
dbg("add dirent to #%llu\n", vc->vno);
chfs_add_node_to_list(chmp, vc, fd->nref, &vc->dirents);
/*tmp = vc->dirents;
dbg("START|vno: %d dirents dump\n", vc->vno);
while (tmp) {
dbg(" ->nref->nref_lnr: %d\n", tmp->lnr);
dbg(" ->nref->nref_offset: %d\n", tmp->offset);
tmp = tmp->next;
}
dbg(" END|vno: %d dirents dump\n", vc->vno);*/
// fd->next = NULL;
fd->vno = le64toh(dirent->vno);
fd->version = le64toh(dirent->version);
fd->nhash = hash32_buf(fd->name, namelen, HASH32_BUF_INIT);
fd->type = dirent->dtype;
/*dbg("dirent dump:\n");
dbg(" ->vno: %d\n", fd->vno);
dbg(" ->version: %ld\n", fd->version);
dbg(" ->nhash: 0x%x\n", fd->nhash);
dbg(" ->nsize: %d\n", fd->nsize);
dbg(" ->name: %s\n", fd->name);
dbg(" ->type: %d\n", fd->type);*/
chfs_add_fd_to_list(chmp, fd, vc);
/*struct chfs_node_ref *tmp;
tmp = vc->dirents;
dbg("START|vno: %d dirents dump\n", vc->vno);
while (tmp) {
dbg(" ->nref->nref_lnr: %d\n", tmp->lnr);
dbg(" ->nref->nref_offset: %d\n", tmp->offset);
tmp = tmp->next;
}
dbg(" END|vno: %d dirents dump\n", vc->vno);*/
/*dbg("dirent dump:\n");
dbg(" ->magic: 0x%x\n", le16toh(dirent->magic));
dbg(" ->type: %d\n", le16toh(dirent->type));
dbg(" ->length: %d\n", le32toh(dirent->length));
dbg(" ->hdr_crc: 0x%x\n", le32toh(dirent->hdr_crc));
dbg(" ->vno: %d\n", le64toh(dirent->vno));
dbg(" ->pvno: %d\n", le64toh(dirent->pvno));
dbg(" ->version: %ld\n", le64toh(dirent->version));
dbg(" ->mctime: %d\n", le32toh(dirent->mctime));
dbg(" ->nsize: %d\n", dirent->nsize);
dbg(" ->dtype: %d\n", dirent->dtype);
dbg(" ->name_crc: 0x%x\n", le32toh(dirent->name_crc));
dbg(" ->node_crc: 0x%x\n", le32toh(dirent->node_crc));
dbg(" ->name: %s\n", dirent->name);*/
return CHFS_NODE_OK;
}
/**
* chfs_scan_check_data_node - check vnode crc and add to vnode cache
* @chmp: CHFS main descriptor structure
* @cheb: eraseblock informations
* @buf: data node to check
* @ofs: offset in eraseblock where data node starts
*/
int
chfs_scan_check_data_node(struct chfs_mount *chmp,
struct chfs_eraseblock *cheb, void *buf, off_t ofs)
{
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
int err;
uint32_t crc, vno;
struct chfs_node_ref *nref;
struct chfs_vnode_cache *vc;
struct chfs_flash_data_node *dnode = buf;
crc = crc32(0, (uint8_t *)dnode, sizeof(struct chfs_flash_data_node) - 4);
if (crc != le32toh(dnode->node_crc)) {
err = chfs_update_eb_dirty(chmp, cheb, le32toh(dnode->length));
if (err)
return err;
return CHFS_NODE_BADCRC;
}
/**
* Don't check data nodes crc and version here, it will be done in
* the background GC thread.
*/
nref = chfs_alloc_node_ref(cheb);
if (!nref)
return ENOMEM;
nref->nref_offset = ofs | CHFS_UNCHECKED_NODE_MASK;
KASSERT(nref->nref_lnr == cheb->lnr);
vno = le64toh(dnode->vno);
mutex_enter(&chmp->chm_lock_vnocache);
vc = chfs_vnode_cache_get(chmp, vno);
if (!vc) {
vc = chfs_scan_make_vnode_cache(chmp, vno);
if (!vc)
return ENOMEM;
}
mutex_exit(&chmp->chm_lock_vnocache);
chfs_add_node_to_list(chmp, vc, nref, &vc->dnode);
dbg("chmpfree: %u, chebfree: %u, dnode: %u\n", chmp->chm_free_size, cheb->free_size, dnode->length);
mutex_enter(&chmp->chm_lock_sizes);
chfs_change_size_free(chmp, cheb, -dnode->length);
chfs_change_size_unchecked(chmp, cheb, dnode->length);
mutex_exit(&chmp->chm_lock_sizes);
return CHFS_NODE_OK;
}
/**
* chfs_scan_classify_cheb - determine eraseblock's state
* @chmp: CHFS main descriptor structure
* @cheb: eraseblock to classify
*/
int
chfs_scan_classify_cheb(struct chfs_mount *chmp,
struct chfs_eraseblock *cheb)
{
if (cheb->free_size == chmp->chm_ebh->eb_size)
return CHFS_BLK_STATE_FREE;
else if (cheb->dirty_size < MAX_DIRTY_TO_CLEAN)
return CHFS_BLK_STATE_CLEAN;
else if (cheb->used_size || cheb->unchecked_size)
return CHFS_BLK_STATE_PARTDIRTY;
else
return CHFS_BLK_STATE_ALLDIRTY;
}
/**
* chfs_scan_eraseblock - scans an eraseblock and looking for nodes
* @chmp: CHFS main descriptor structure
* @cheb: eraseblock to scan
*
* This function scans a whole eraseblock, checks the nodes on it and add them
* to the vnode cache.
* Returns eraseblock state on success, error code if fails.
*/
int
chfs_scan_eraseblock(struct chfs_mount *chmp,
struct chfs_eraseblock *cheb) {
int err;
size_t len, retlen;
off_t ofs = 0;
int lnr = cheb->lnr;
u_char *buf;
struct chfs_flash_node_hdr *nhdr;
int read_free = 0;
struct chfs_node_ref *nref;
dbg("scanning eraseblock content: %d free_size: %d\n", cheb->lnr, cheb->free_size);
dbg("scanned physical block: %d\n", chmp->chm_ebh->lmap[lnr]);
buf = kmem_alloc(CHFS_MAX_NODE_SIZE, KM_SLEEP);
while((ofs + CHFS_NODE_HDR_SIZE) < chmp->chm_ebh->eb_size) {
memset(buf, 0 , CHFS_MAX_NODE_SIZE);
err = chfs_read_leb(chmp,
lnr, buf, ofs, CHFS_NODE_HDR_SIZE, &retlen);
if (err) {
return err;
}
if (retlen != CHFS_NODE_HDR_SIZE) {
chfs_err("Error reading node header: "
"read: %zu instead of: %zu\n",
CHFS_NODE_HDR_SIZE, retlen);
return EIO;
}
/* first we check if the buffer we read is full with 0xff, if yes maybe
* the blocks remaining area is free. We increase read_free and if it
* reaches MAX_READ_FREE we stop reading the block*/
if (check_pattern(buf, 0xff, 0, CHFS_NODE_HDR_SIZE)) {
read_free += CHFS_NODE_HDR_SIZE;
if (read_free >= MAX_READ_FREE(chmp)) {
dbg("rest of the block is free. Size: %d\n", cheb->free_size);
return chfs_scan_classify_cheb(chmp, cheb);
}
ofs += CHFS_NODE_HDR_SIZE;
continue;
} else {
chfs_update_eb_dirty(chmp, cheb, read_free);
read_free = 0;
}
nhdr = (struct chfs_flash_node_hdr *)buf;
err = chfs_scan_check_node_hdr(nhdr);
if (err) {
dbg("node hdr error\n");
err = chfs_update_eb_dirty(chmp, cheb, 4);
if (err) {
return err;
}
ofs += 4;
continue;
}
ofs += CHFS_NODE_HDR_SIZE;
if (ofs > chmp->chm_ebh->eb_size) {
chfs_err("Second part of node is on the next eraseblock.\n");
return EIO;
}
switch (le16toh(nhdr->type)) {
case CHFS_NODETYPE_VNODE:
/* Read up the node */
//dbg("nodetype vnode\n");
len = le32toh(nhdr->length) - CHFS_NODE_HDR_SIZE;
err = chfs_read_leb(chmp,
lnr, buf + CHFS_NODE_HDR_SIZE,
ofs, len, &retlen);
if (err) {
return err;
}
if (retlen != len) {
chfs_err("Error reading vnode: read: %zu instead of: %zu\n",
len, retlen);
return EIO;
}
KASSERT(lnr == cheb->lnr);
err = chfs_scan_check_vnode(chmp,
cheb, buf, ofs - CHFS_NODE_HDR_SIZE);
if (err) {
return err;
}
//dbg("XXX5end\n");
break;
case CHFS_NODETYPE_DIRENT:
/* Read up the node */
//dbg("nodetype dirent\n");
len = le32toh(nhdr->length) - CHFS_NODE_HDR_SIZE;
err = chfs_read_leb(chmp,
lnr, buf + CHFS_NODE_HDR_SIZE,
ofs, len, &retlen);
if (err) {
return err;
}
if (retlen != len) {
chfs_err("Error reading dirent node: read: %zu "
"instead of: %zu\n", len, retlen);
return EIO;
}
KASSERT(lnr == cheb->lnr);
err = chfs_scan_check_dirent_node(chmp,
cheb, buf, ofs - CHFS_NODE_HDR_SIZE);
if (err) {
return err;
}
//dbg("XXX6end\n");
break;
case CHFS_NODETYPE_DATA:
//dbg("nodetype data\n");
len = sizeof(struct chfs_flash_data_node) -
CHFS_NODE_HDR_SIZE;
err = chfs_read_leb(chmp,
lnr, buf + CHFS_NODE_HDR_SIZE,
ofs, len, &retlen);
if (err) {
return err;
}
if (retlen != len) {
chfs_err("Error reading data node: read: %zu "
"instead of: %zu\n", len, retlen);
return EIO;
}
KASSERT(lnr == cheb->lnr);
err = chfs_scan_check_data_node(chmp,
cheb, buf, ofs - CHFS_NODE_HDR_SIZE);
if (err)
return err;
//dbg("XXX7end\n");
break;
case CHFS_NODETYPE_PADDING:
//dbg("nodetype padding\n");
//dbg("padding len: %d\n", le32toh(nhdr->length));
//dbg("BEF: cheb->free_size: %d\n", cheb->free_size);
nref = chfs_alloc_node_ref(cheb);
nref->nref_offset = ofs - CHFS_NODE_HDR_SIZE;
nref->nref_offset = CHFS_GET_OFS(nref->nref_offset) |
CHFS_OBSOLETE_NODE_MASK;
err = chfs_update_eb_dirty(chmp, cheb,
le32toh(nhdr->length));
//dbg("AFT: cheb->free_size: %d\n", cheb->free_size);
if (err)
return err;
//dbg("XXX8end\n");
break;
default:
//dbg("nodetype ? (default)\n");
/* Unknown node type, update dirty and skip */
err = chfs_update_eb_dirty(chmp, cheb,
le32toh(nhdr->length));
if (err)
return err;
//dbg("XXX9end\n");
break;
}
ofs += le32toh(nhdr->length) - CHFS_NODE_HDR_SIZE;
}
KASSERT(cheb->used_size + cheb->free_size + cheb->dirty_size +
cheb->unchecked_size + cheb->wasted_size == chmp->chm_ebh->eb_size);
//dbg("XXX10\n");
return chfs_scan_classify_cheb(chmp, cheb);
}

539
sys/ufs/chfs/chfs_subr.c Normal file
View File

@ -0,0 +1,539 @@
/* $NetBSD: chfs_subr.c,v 1.1 2011/11/24 15:51:31 ahoka Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
* University of Szeged, Hungary
* Copyright (C) 2010 Tamas Toth <ttoth@inf.u-szeged.hu>
* Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* 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.
*/
/*
* Efficient memory file system supporting functions.
*/
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/dirent.h>
#include <sys/event.h>
#include <sys/kmem.h>
#include <sys/mount.h>
#include <sys/namei.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/systm.h>
#include <sys/swap.h>
#include <sys/vnode.h>
#include <sys/kauth.h>
#include <sys/proc.h>
#include <sys/atomic.h>
#include <uvm/uvm.h>
#include <miscfs/specfs/specdev.h>
#include "chfs.h"
//#include <fs/chfs/chfs_vnops.h>
//#include </root/xipffs/netbsd.chfs/chfs.h>
/* --------------------------------------------------------------------- */
/*
* Returns information about the number of available memory pages,
* including physical and virtual ones.
*
* If 'total' is true, the value returned is the total amount of memory
* pages configured for the system (either in use or free).
* If it is FALSE, the value returned is the amount of free memory pages.
*
* Remember to remove DUMMYFS_PAGES_RESERVED from the returned value to avoid
* excessive memory usage.
*
*/
size_t
chfs_mem_info(bool total)
{
size_t size;
size = 0;
size += uvmexp.swpgavail;
if (!total) {
size -= uvmexp.swpgonly;
}
size += uvmexp.free;
size += uvmexp.filepages;
if (size > uvmexp.wired) {
size -= uvmexp.wired;
} else {
size = 0;
}
return size;
}
/* --------------------------------------------------------------------- */
/*
* Looks for a directory entry in the directory represented by node.
* 'cnp' describes the name of the entry to look for. Note that the .
* and .. components are not allowed as they do not physically exist
* within directories.
*
* Returns a pointer to the entry when found, otherwise NULL.
*/
struct chfs_dirent *
chfs_dir_lookup(struct chfs_inode *ip, struct componentname *cnp)
{
bool found;
struct chfs_dirent *fd;
dbg("dir_lookup()\n");
KASSERT(IMPLIES(cnp->cn_namelen == 1, cnp->cn_nameptr[0] != '.'));
KASSERT(IMPLIES(cnp->cn_namelen == 2, !(cnp->cn_nameptr[0] == '.' &&
cnp->cn_nameptr[1] == '.')));
//CHFS_VALIDATE_DIR(node);
//node->chn_status |= CHFS_NODE_ACCESSED;
found = false;
// fd = ip->dents;
// while(fd) {
TAILQ_FOREACH(fd, &ip->dents, fds) {
KASSERT(cnp->cn_namelen < 0xffff);
if (fd->vno == 0)
continue;
/*dbg("dirent dump:\n");
dbg(" ->vno: %d\n", fd->vno);
dbg(" ->version: %ld\n", fd->version);
dbg(" ->nhash: 0x%x\n", fd->nhash);
dbg(" ->nsize: %d\n", fd->nsize);
dbg(" ->name: %s\n", fd->name);
dbg(" ->type: %d\n", fd->type);*/
if (fd->nsize == (uint16_t)cnp->cn_namelen &&
memcmp(fd->name, cnp->cn_nameptr, fd->nsize) == 0) {
found = true;
break;
}
// fd = fd->next;
}
return found ? fd : NULL;
}
/* --------------------------------------------------------------------- */
int
chfs_filldir(struct uio* uio, ino_t ino, const char *name,
int namelen, enum vtype type)
{
struct dirent dent;
int error;
memset(&dent, 0, sizeof(dent));
dent.d_fileno = ino;
switch (type) {
case VBLK:
dent.d_type = DT_BLK;
break;
case VCHR:
dent.d_type = DT_CHR;
break;
case VDIR:
dent.d_type = DT_DIR;
break;
case VFIFO:
dent.d_type = DT_FIFO;
break;
case VLNK:
dent.d_type = DT_LNK;
break;
case VREG:
dent.d_type = DT_REG;
break;
case VSOCK:
dent.d_type = DT_SOCK;
break;
default:
KASSERT(0);
}
dent.d_namlen = namelen;
(void)memcpy(dent.d_name, name, dent.d_namlen);
dent.d_reclen = _DIRENT_SIZE(&dent);
if (dent.d_reclen > uio->uio_resid) {
error = -1;
} else {
error = uiomove(&dent, dent.d_reclen, uio);
}
return error;
}
/* --------------------------------------------------------------------- */
/*
* Change size of the given vnode.
* Caller should execute chfs_update on vp after a successful execution.
* The vnode must be locked on entry and remain locked on exit.
*/
int
chfs_chsize(struct vnode *vp, u_quad_t size, kauth_cred_t cred)
{
struct chfs_mount *chmp;
struct chfs_inode *ip;
struct buf *bp;
int blknum, append;
int error = 0;
char *buf = NULL;
struct chfs_full_dnode *fd;
ip = VTOI(vp);
chmp = ip->chmp;
dbg("chfs_chsize\n");
switch (vp->v_type) {
case VDIR:
return EISDIR;
case VLNK:
case VREG:
if (vp->v_mount->mnt_flag & MNT_RDONLY)
return EROFS;
break;
case VBLK:
case VCHR:
case VFIFO:
return 0;
default:
return EOPNOTSUPP; /* XXX why not ENODEV? */
}
vflushbuf(vp, 0);
mutex_enter(&chmp->chm_lock_mountfields);
chfs_flush_pending_wbuf(chmp);
/* handle truncate to zero as a special case */
if (size == 0) {
dbg("truncate to zero");
chfs_truncate_fragtree(ip->chmp,
&ip->fragtree, size);
chfs_set_vnode_size(vp, size);
mutex_exit(&chmp->chm_lock_mountfields);
return 0;
}
/* allocate zeros for the new data */
buf = kmem_zalloc(size, KM_SLEEP);
bp = getiobuf(vp, true);
if (ip->size != 0) {
/* read the whole data */
bp->b_blkno = 0;
bp->b_bufsize = bp->b_resid = bp->b_bcount = ip->size;
bp->b_data = kmem_alloc(ip->size, KM_SLEEP);
error = chfs_read_data(chmp, vp, bp);
if (error) {
mutex_exit(&chmp->chm_lock_mountfields);
putiobuf(bp);
return error;
}
/* create the new data */
dbg("create new data vap%llu ip%llu\n", size, ip->size);
append = size - ip->size;
if (append > 0) {
memcpy(buf, bp->b_data, ip->size);
} else {
memcpy(buf, bp->b_data, size);
chfs_truncate_fragtree(ip->chmp,
&ip->fragtree, size);
}
kmem_free(bp->b_data, ip->size);
struct chfs_node_frag *lastfrag = frag_last(&ip->fragtree);
fd = lastfrag->node;
chfs_mark_node_obsolete(chmp, fd->nref);
blknum = lastfrag->ofs / PAGE_SIZE;
lastfrag->size = append > PAGE_SIZE ? PAGE_SIZE : size % PAGE_SIZE;
} else {
fd = chfs_alloc_full_dnode();
blknum = 0;
}
chfs_set_vnode_size(vp, size);
// write the new data
for (bp->b_blkno = blknum; bp->b_blkno * PAGE_SIZE < size; bp->b_blkno++) {
uint64_t writesize = MIN(size - bp->b_blkno * PAGE_SIZE, PAGE_SIZE);
bp->b_bufsize = bp->b_resid = bp->b_bcount = writesize;
bp->b_data = kmem_alloc(writesize, KM_SLEEP);
memcpy(bp->b_data, buf + (bp->b_blkno * PAGE_SIZE), writesize);
if (bp->b_blkno != blknum) {
fd = chfs_alloc_full_dnode();
}
error = chfs_write_flash_dnode(chmp, vp, bp, fd);
if (error) {
mutex_exit(&chmp->chm_lock_mountfields);
kmem_free(bp->b_data, writesize);
putiobuf(bp);
return error;
}
if (bp->b_blkno != blknum) {
chfs_add_full_dnode_to_inode(chmp, ip, fd);
}
kmem_free(bp->b_data, writesize);
}
mutex_exit(&chmp->chm_lock_mountfields);
kmem_free(buf, size);
putiobuf(bp);
return 0;
}
#if 0
int error;
struct chfs_node *node;
KASSERT(VOP_ISLOCKED(vp));
node = VP_TO_CHFS_NODE(vp);
// Decide whether this is a valid operation based on the file type.
error = 0;
switch (vp->v_type) {
case VDIR:
return EISDIR;
case VREG:
if (vp->v_mount->mnt_flag & MNT_RDONLY)
return EROFS;
break;
case VBLK:
case VCHR:
case VFIFO:
// Allow modifications of special files even if in the file
// system is mounted read-only (we are not modifying the
// files themselves, but the objects they represent).
return 0;
default:
return ENODEV;
}
// Immutable or append-only files cannot be modified, either.
if (node->chn_flags & (IMMUTABLE | APPEND))
return EPERM;
error = chfs_truncate(vp, size);
// chfs_truncate will raise the NOTE_EXTEND and NOTE_ATTRIB kevents
// for us, as will update dn_status; no need to do that here.
KASSERT(VOP_ISLOCKED(vp));
return error;
#endif
/* --------------------------------------------------------------------- */
/*
* Change flags of the given vnode.
* Caller should execute chfs_update on vp after a successful execution.
* The vnode must be locked on entry and remain locked on exit.
*/
int
chfs_chflags(struct vnode *vp, int flags, kauth_cred_t cred)
{
struct chfs_mount *chmp;
struct chfs_inode *ip;
int error = 0;
ip = VTOI(vp);
chmp = ip->chmp;
if (vp->v_mount->mnt_flag & MNT_RDONLY)
return EROFS;
if (kauth_cred_geteuid(cred) != ip->uid &&
(error = kauth_authorize_generic(cred,
KAUTH_GENERIC_ISSUSER, NULL)))
return error;
if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
NULL) == 0) {
if ((ip->flags & (SF_IMMUTABLE | SF_APPEND)) &&
kauth_authorize_system(curlwp->l_cred,
KAUTH_SYSTEM_CHSYSFLAGS, 0, NULL, NULL, NULL))
return EPERM;
if ((flags & SF_SNAPSHOT) !=
(ip->flags & SF_SNAPSHOT))
return EPERM;
ip->flags = flags;
} else {
if ((ip->flags & (SF_IMMUTABLE | SF_APPEND)) ||
(flags & UF_SETTABLE) != flags)
return EPERM;
if ((ip->flags & SF_SETTABLE) !=
(flags & SF_SETTABLE))
return EPERM;
ip->flags &= SF_SETTABLE;
ip->flags |= (flags & UF_SETTABLE);
}
ip->iflag |= IN_CHANGE;
error = chfs_update(vp, NULL, NULL, UPDATE_WAIT);
if (error)
return error;
if (flags & (IMMUTABLE | APPEND))
return 0;
return error;
}
/* --------------------------------------------------------------------- */
void
chfs_itimes(struct chfs_inode *ip, const struct timespec *acc,
const struct timespec *mod, const struct timespec *cre)
{
//dbg("itimes\n");
struct timespec now;
if (!(ip->iflag & (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY))) {
return;
}
vfs_timestamp(&now);
if (ip->iflag & IN_ACCESS) {
if (acc == NULL)
acc = &now;
ip->atime = acc->tv_sec;
}
if (ip->iflag & (IN_UPDATE | IN_MODIFY)) {
if (mod == NULL)
mod = &now;
ip->mtime = mod->tv_sec;
//ip->i_modrev++;
}
if (ip->iflag & (IN_CHANGE | IN_MODIFY)) {
if (cre == NULL)
cre = &now;
ip->ctime = cre->tv_sec;
}
if (ip->iflag & (IN_ACCESS | IN_MODIFY))
ip->iflag |= IN_ACCESSED;
if (ip->iflag & (IN_UPDATE | IN_CHANGE))
ip->iflag |= IN_MODIFIED;
ip->iflag &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY);
}
/* --------------------------------------------------------------------- */
int
chfs_update(struct vnode *vp, const struct timespec *acc,
const struct timespec *mod, int flags)
{
struct chfs_inode *ip;
/* XXX ufs_reclaim calls this function unlocked! */
// KASSERT(VOP_ISLOCKED(vp));
#if 0
if (flags & UPDATE_CLOSE)
; /* XXX Need to do anything special? */
#endif
ip = VTOI(vp);
chfs_itimes(ip, acc, mod, NULL);
// KASSERT(VOP_ISLOCKED(vp));
return (0);
}
/* --------------------------------------------------------------------- */
/*
int
chfs_truncate(struct vnode *vp, off_t length)
{
bool extended;
int error;
struct chfs_node *node;
printf("CHFS: truncate()\n");
node = VP_TO_CHFS_NODE(vp);
extended = length > node->chn_size;
if (length < 0) {
error = EINVAL;
goto out;
}
if (node->chn_size == length) {
error = 0;
goto out;
}
error = chfs_reg_resize(vp, length);
if (error == 0)
node->chn_status |= CHFS_NODE_CHANGED | CHFS_NODE_MODIFIED;
out:
chfs_update(vp, NULL, NULL, 0);
return error;
}*/

844
sys/ufs/chfs/chfs_vfsops.c Normal file
View File

@ -0,0 +1,844 @@
/* $NetBSD: chfs_vfsops.c,v 1.1 2011/11/24 15:51:32 ahoka Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
* University of Szeged, Hungary
* Copyright (C) 2010 Tamas Toth <ttoth@inf.u-szeged.hu>
* Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* 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 <sys/cdefs.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/kmem.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/module.h>
#include <sys/namei.h>
#include <sys/malloc.h>
#include <sys/fcntl.h>
#include <sys/conf.h>
#include <sys/buf.h>
//XXX needed just for debugging
#include <sys/fstrans.h>
#include <sys/sleepq.h>
#include <sys/lockdebug.h>
#include <sys/ktrace.h>
#include <uvm/uvm.h>
#include <uvm/uvm_pager.h>
#include <ufs/ufs/dir.h>
//#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufs_extern.h>
#include <miscfs/genfs/genfs.h>
#include <miscfs/genfs/genfs_node.h>
#include <miscfs/specfs/specdev.h>
//#include </root/xipffs/netbsd.chfs/chfs.h>
//#include </root/xipffs/netbsd.chfs/chfs_args.h>
#include "chfs.h"
#include "chfs_args.h"
MODULE(MODULE_CLASS_VFS, chfs, "flash");
/* --------------------------------------------------------------------- */
/* functions */
static int chfs_mount(struct mount *, const char *, void *, size_t *);
static int chfs_unmount(struct mount *, int);
static int chfs_root(struct mount *, struct vnode **);
static int chfs_vget(struct mount *, ino_t, struct vnode **);
static int chfs_fhtovp(struct mount *, struct fid *, struct vnode **);
static int chfs_vptofh(struct vnode *, struct fid *, size_t *);
static int chfs_start(struct mount *, int);
static int chfs_statvfs(struct mount *, struct statvfs *);
static int chfs_sync(struct mount *, int, kauth_cred_t);
static void chfs_init(void);
static void chfs_reinit(void);
static void chfs_done(void);
static int chfs_snapshot(struct mount *, struct vnode *,
struct timespec *);
/* --------------------------------------------------------------------- */
/* structures */
int
chfs_gop_alloc(struct vnode *vp, off_t off, off_t len, int flags,
kauth_cred_t cred)
{
return (0);
}
const struct genfs_ops chfs_genfsops = {
.gop_size = genfs_size,
.gop_alloc = chfs_gop_alloc,
.gop_write = genfs_gop_write,
.gop_markupdate = ufs_gop_markupdate,
};
/*
static const struct ufs_ops chfs_ufsops = {
.uo_itimes = chfs_itimes,
.uo_update = chfs_update,
};
*/
struct pool chfs_inode_pool;
/* for looking up the major for flash */
extern const struct cdevsw flash_cdevsw;
/* --------------------------------------------------------------------- */
static int
chfs_mount(struct mount *mp,
const char *path, void *data, size_t *data_len)
{
struct lwp *l = curlwp;
struct nameidata nd;
struct pathbuf *pb;
struct vnode *devvp = NULL;
struct ufs_args *args = data;
struct ufsmount *ump = NULL;
struct chfs_mount *chmp;
int err = 0;
int xflags;
dbg("mount()\n");
if (*data_len < sizeof *args)
return EINVAL;
if (mp->mnt_flag & MNT_GETARGS) {
ump = VFSTOUFS(mp);
if (ump == NULL)
return EIO;
memset(args, 0, sizeof *args);
args->fspec = NULL;
*data_len = sizeof *args;
return 0;
}
if (mp->mnt_flag & MNT_UPDATE) {
/* XXX: There is no support yet to update file system
* settings. Should be added. */
return ENODEV;
}
if (args->fspec != NULL) {
err = pathbuf_copyin(args->fspec, &pb);
if (err) {
return err;
}
/*
* Look up the name and verify that it's sane.
*/
NDINIT(&nd, LOOKUP, FOLLOW, pb);
if ((err = namei(&nd)) != 0 )
return (err);
devvp = nd.ni_vp;
/*
* Be sure this is a valid block device
*/
if (devvp->v_type != VBLK)
err = ENOTBLK;
else if (bdevsw_lookup(devvp->v_rdev) == NULL)
err = ENXIO;
}
if (err) {
vrele(devvp);
return (err);
}
if (mp->mnt_flag & MNT_RDONLY)
xflags = FREAD;
else
xflags = FREAD|FWRITE;
err = VOP_OPEN(devvp, xflags, FSCRED);
if (err)
goto fail;
err = chfs_mountfs(devvp, mp);
if (err) {
vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
(void)VOP_CLOSE(devvp, xflags, NOCRED);
VOP_UNLOCK(devvp);
goto fail;
}
ump = VFSTOUFS(mp);
chmp = ump->um_chfs;
vfs_getnewfsid(mp);
chmp->chm_fsmp = mp;
return set_statvfs_info(path,
UIO_USERSPACE, args->fspec,
UIO_USERSPACE, mp->mnt_op->vfs_name, mp, l);
fail:
vrele(devvp);
return (err);
}
int
chfs_mountfs(struct vnode *devvp, struct mount *mp)
{
struct lwp *l = curlwp;
struct proc *p;
kauth_cred_t cred;
devmajor_t flash_major;
dev_t dev;
struct ufsmount* ump = NULL;
struct chfs_mount* chmp;
struct vnode *vp;
int err = 0;
dbg("mountfs()\n");
dev = devvp->v_rdev;
p = l ? l->l_proc : NULL;
cred = l ? l->l_cred : NOCRED;
/* Flush out any old buffers remaining from a previous use. */
vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
err = vinvalbuf(devvp, V_SAVE, cred, l, 0, 0);
VOP_UNLOCK(devvp);
if (err)
return (err);
flash_major = cdevsw_lookup_major(&flash_cdevsw);
if (devvp->v_type != VBLK)
err = ENOTBLK;
else if (bdevsw_lookup(dev) == NULL)
err = ENXIO;
else if (major(dev) != flash_major) {
dbg("major(dev): %d, flash_major: %d\n",
major(dev), flash_major);
err = ENODEV;
}
if (err) {
vrele(devvp);
return (err);
}
ump = malloc(sizeof(*ump), M_UFSMNT, M_WAITOK);
memset(ump, 0, sizeof(*ump));
ump->um_fstype = UFS1;
//ump->um_ops = &chfs_ufsops;
ump->um_chfs = malloc(sizeof(struct chfs_mount),
M_UFSMNT, M_WAITOK);
memset(ump->um_chfs, 0, sizeof(struct chfs_mount));
mutex_init(&ump->um_lock, MUTEX_DEFAULT, IPL_NONE);
/* Get superblock and set flash device number */
chmp = ump->um_chfs;
if (!chmp)
return ENOMEM;
chmp->chm_ebh = kmem_alloc(sizeof(struct chfs_ebh), KM_SLEEP);
dbg("[]opening flash: %u\n", (unsigned int)devvp->v_rdev);
err = ebh_open(chmp->chm_ebh, devvp->v_rdev);
if (err) {
dbg("error while opening flash\n");
kmem_free(chmp->chm_ebh, sizeof(struct chfs_ebh));
free(chmp, M_UFSMNT);
return err;
}
//TODO check flash sizes
chmp->chm_gbl_version = 0;
chmp->chm_vnocache_hash = chfs_vnocache_hash_init();
chmp->chm_blocks = kmem_zalloc(chmp->chm_ebh->peb_nr *
sizeof(struct chfs_eraseblock), KM_SLEEP);
if (!chmp->chm_blocks) {
kmem_free(chmp->chm_ebh, chmp->chm_ebh->peb_nr *
sizeof(struct chfs_eraseblock));
ebh_close(chmp->chm_ebh);
free(chmp, M_UFSMNT);
return ENOMEM;
}
mutex_init(&chmp->chm_lock_mountfields, MUTEX_DEFAULT, IPL_NONE);
mutex_init(&chmp->chm_lock_sizes, MUTEX_DEFAULT, IPL_NONE);
mutex_init(&chmp->chm_lock_vnocache, MUTEX_DEFAULT, IPL_NONE);
//XXX
chmp->chm_fs_bmask = -4096;
chmp->chm_fs_bsize = 4096;
chmp->chm_fs_qbmask = 4095;
chmp->chm_fs_bshift = 12;
chmp->chm_fs_fmask = -2048;
chmp->chm_fs_qfmask = 2047;
chmp->chm_wbuf_pagesize = chmp->chm_ebh->flash_if->page_size;
dbg("wbuf size: %zu\n", chmp->chm_wbuf_pagesize);
chmp->chm_wbuf = kmem_alloc(chmp->chm_wbuf_pagesize, KM_SLEEP);
rw_init(&chmp->chm_lock_wbuf);
//init queues
TAILQ_INIT(&chmp->chm_free_queue);
TAILQ_INIT(&chmp->chm_clean_queue);
TAILQ_INIT(&chmp->chm_dirty_queue);
TAILQ_INIT(&chmp->chm_very_dirty_queue);
TAILQ_INIT(&chmp->chm_erasable_pending_wbuf_queue);
TAILQ_INIT(&chmp->chm_erase_pending_queue);
chfs_calc_trigger_levels(chmp);
chmp->chm_nr_free_blocks = 0;
chmp->chm_nr_erasable_blocks = 0;
chmp->chm_max_vno = 2;
chmp->chm_checked_vno = 2;
chmp->chm_unchecked_size = 0;
chmp->chm_used_size = 0;
chmp->chm_dirty_size = 0;
chmp->chm_wasted_size = 0;
chmp->chm_free_size = chmp->chm_ebh->eb_size * chmp->chm_ebh->peb_nr;
err = chfs_build_filesystem(chmp);
if (err) {
chfs_vnocache_hash_destroy(chmp->chm_vnocache_hash);
kmem_free(chmp->chm_ebh, chmp->chm_ebh->peb_nr *
sizeof(struct chfs_eraseblock));
ebh_close(chmp->chm_ebh);
free(chmp, M_UFSMNT);
return EIO;
}
mp->mnt_data = ump;
mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)dev;
mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_CHFS);
mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
mp->mnt_stat.f_namemax = MAXNAMLEN;
mp->mnt_flag |= MNT_LOCAL;
mp->mnt_fs_bshift = PAGE_SHIFT;
mp->mnt_dev_bshift = DEV_BSHIFT;
mp->mnt_iflag |= IMNT_MPSAFE;
ump->um_flags = 0;
ump->um_mountp = mp;
ump->um_dev = dev;
ump->um_devvp = devvp;
ump->um_maxfilesize = 1048512 * 1024;
/*TODO fill these fields
ump->um_nindir =
ump->um_lognindir =
ump->um_bptrtodb =
ump->um_seqinc =
ump->um_maxsymlinklen =
ump->um_dirblksiz =
ump->um_maxfilesize =
*/
/*
* Allocate the root vnode.
*/
err = VFS_VGET(mp, CHFS_ROOTINO, &vp);
if (err) {
dbg("error: %d while allocating root node\n", err);
return err;
}
vput(vp);
chfs_gc_thread_start(chmp);
mutex_enter(&chmp->chm_lock_mountfields);
chfs_gc_trigger(chmp);
mutex_exit(&chmp->chm_lock_mountfields);
devvp->v_specmountpoint = mp;
return 0;
}
/* --------------------------------------------------------------------- */
/* ARGSUSED2 */
static int
chfs_unmount(struct mount *mp, int mntflags)
{
int flags = 0, i = 0;
struct ufsmount *ump;
struct chfs_mount *chmp;
// struct chfs_vnode_cache *vc, *next;
if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
dbg("[START]\n");
ump = VFSTOUFS(mp);
chmp = ump->um_chfs;
chfs_gc_thread_stop(chmp);
(void)vflush(mp, NULLVP, flags);
if (chmp->chm_wbuf_len) {
mutex_enter(&chmp->chm_lock_mountfields);
chfs_flush_pending_wbuf(chmp);
mutex_exit(&chmp->chm_lock_mountfields);
}
for (i = 0; i < chmp->chm_ebh->peb_nr; i++) {
chfs_free_node_refs(&chmp->chm_blocks[i]);
}
chfs_vnocache_hash_destroy(chmp->chm_vnocache_hash);
ebh_close(chmp->chm_ebh);
rw_destroy(&chmp->chm_lock_wbuf);
mutex_destroy(&chmp->chm_lock_vnocache);
mutex_destroy(&chmp->chm_lock_sizes);
mutex_destroy(&chmp->chm_lock_mountfields);
if (ump->um_devvp->v_type != VBAD) {
ump->um_devvp->v_specmountpoint = NULL;
}
vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY);
(void)VOP_CLOSE(ump->um_devvp, FREAD|FWRITE, NOCRED);
vput(ump->um_devvp);
mutex_destroy(&ump->um_lock);
//free(ump->um_chfs, M_UFSMNT);
free(ump, M_UFSMNT);
mp->mnt_data = NULL;
mp->mnt_flag &= ~MNT_LOCAL;
dbg("[END]\n");
return (0);
}
/* --------------------------------------------------------------------- */
static int
chfs_root(struct mount *mp, struct vnode **vpp)
{
struct vnode *vp;
int error;
if ((error = VFS_VGET(mp, (ino_t)ROOTINO, &vp)) != 0)
return error;
*vpp = vp;
return 0;
}
/* --------------------------------------------------------------------- */
extern rb_tree_ops_t frag_rbtree_ops;
static int
chfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
{
struct chfs_mount *chmp;
struct chfs_inode *ip;
struct ufsmount *ump;
struct vnode *vp;
dev_t dev;
int error;
struct chfs_vnode_cache* chvc = NULL;
struct chfs_node_ref* nref = NULL;
struct buf *bp;
dbg("vget() | ino: %llu\n", ino);
ump = VFSTOUFS(mp);
dev = ump->um_dev;
retry:
if (!vpp) {
vpp = kmem_alloc(sizeof(struct vnode*), KM_SLEEP);
}
if ((*vpp = chfs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL) {
return 0;
}
/* Allocate a new vnode/inode. */
if ((error = getnewvnode(VT_CHFS,
mp, chfs_vnodeop_p, NULL, &vp)) != 0) {
*vpp = NULL;
return (error);
}
ip = pool_get(&chfs_inode_pool, PR_WAITOK);
mutex_enter(&chfs_hashlock);
if ((*vpp = chfs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL) {
mutex_exit(&chfs_hashlock);
ungetnewvnode(vp);
pool_put(&chfs_inode_pool, ip);
goto retry;
}
vp->v_vflag |= VV_LOCKSWORK;
memset(ip, 0, sizeof(*ip));
vp->v_data = ip;
ip->vp = vp;
ip->ump = ump;
ip->chmp = chmp = ump->um_chfs;
ip->dev = dev;
ip->ino = ino;
vp->v_mount = mp;
genfs_node_init(vp, &chfs_genfsops);
rb_tree_init(&ip->fragtree, &frag_rbtree_ops);
//mutex_init(&ip->inode_lock, MUTEX_DEFAULT, IPL_NONE);
chfs_ihashins(ip);
mutex_exit(&chfs_hashlock);
// set root inode
if (ino == CHFS_ROOTINO) {
dbg("SETROOT\n");
vp->v_vflag |= VV_ROOT;
vp->v_type = VDIR;
ip->mode = IFMT | IEXEC | IWRITE | IREAD;
ip->iflag |= (IN_ACCESS | IN_CHANGE | IN_UPDATE);
chfs_update(vp, NULL, NULL, UPDATE_WAIT);
// ip->dents = NULL; XXXTAILQ
TAILQ_INIT(&ip->dents);
chfs_set_vnode_size(vp, 512);
}
// set vnode cache
mutex_enter(&chmp->chm_lock_vnocache);
chvc = chfs_vnode_cache_get(chmp, ino);
mutex_exit(&chmp->chm_lock_vnocache);
if (!chvc) {
dbg("!chvc\n");
/* XXX, we cant alloc under a lock, refactor this! */
chvc = chfs_vnode_cache_alloc(ino);
mutex_enter(&chmp->chm_lock_vnocache);
if (ino == CHFS_ROOTINO) {
chvc->nlink = 2;
chvc->pvno = CHFS_ROOTINO;
chfs_vnode_cache_set_state(chmp,
chvc, VNO_STATE_CHECKEDABSENT);
}
chfs_vnode_cache_add(chmp, chvc);
mutex_exit(&chmp->chm_lock_vnocache);
ip->chvc = chvc;
TAILQ_INIT(&ip->dents);
} else {
dbg("chvc\n");
ip->chvc = chvc;
// if we have a vnode cache, the node is already on flash, so read it
if (ino == CHFS_ROOTINO) {
chvc->pvno = CHFS_ROOTINO;
TAILQ_INIT(&chvc->scan_dirents);
} else {
chfs_readvnode(mp, ino, &vp);
}
mutex_enter(&chmp->chm_lock_mountfields);
// init type specific things
switch (vp->v_type) {
case VDIR:
nref = chvc->dirents;
while (nref &&
(struct chfs_vnode_cache *)nref != chvc) {
chfs_readdirent(mp, nref, ip);
nref = nref->nref_next;
}
chfs_set_vnode_size(vp, 512);
break;
case VREG:
case VSOCK:
//build the fragtree of the vnode
dbg("read_inode_internal | ino: %llu\n", ip->ino);
error = chfs_read_inode(chmp, ip);
if (error) {
vput(vp);
*vpp = NULL;
mutex_exit(&chmp->chm_lock_mountfields);
return (error);
}
break;
case VLNK:
//build the fragtree of the vnode
dbg("read_inode_internal | ino: %llu\n", ip->ino);
error = chfs_read_inode_internal(chmp, ip);
if (error) {
vput(vp);
*vpp = NULL;
mutex_exit(&chmp->chm_lock_mountfields);
return (error);
}
dbg("size: %llu\n", ip->size);
bp = getiobuf(vp, true);
bp->b_blkno = 0;
bp->b_bufsize = bp->b_resid =
bp->b_bcount = ip->size;
bp->b_data = kmem_alloc(ip->size, KM_SLEEP);
chfs_read_data(chmp, vp, bp);
if (!ip->target)
ip->target = kmem_alloc(ip->size,
KM_SLEEP);
memcpy(ip->target, bp->b_data, ip->size);
kmem_free(bp->b_data, ip->size);
putiobuf(bp);
break;
case VCHR:
case VBLK:
case VFIFO:
//build the fragtree of the vnode
dbg("read_inode_internal | ino: %llu\n", ip->ino);
error = chfs_read_inode_internal(chmp, ip);
if (error) {
vput(vp);
*vpp = NULL;
mutex_exit(&chmp->chm_lock_mountfields);
return (error);
}
bp = getiobuf(vp, true);
bp->b_blkno = 0;
bp->b_bufsize = bp->b_resid =
bp->b_bcount = sizeof(dev_t);
bp->b_data = kmem_alloc(sizeof(dev_t), KM_SLEEP);
chfs_read_data(chmp, vp, bp);
memcpy(&ip->rdev,
bp->b_data, sizeof(dev_t));
kmem_free(bp->b_data, sizeof(dev_t));
putiobuf(bp);
if (vp->v_type == VFIFO)
vp->v_op = chfs_fifoop_p;
else {
vp->v_op = chfs_specop_p;
spec_node_init(vp, ip->rdev);
}
break;
case VNON:
case VBAD:
break;
}
mutex_exit(&chmp->chm_lock_mountfields);
}
/* finish inode initalization */
ip->devvp = ump->um_devvp;
vref(ip->devvp);
uvm_vnp_setsize(vp, ip->size);
*vpp = vp;
return 0;
}
/* --------------------------------------------------------------------- */
static int
chfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
{
return ENODEV;
}
/* --------------------------------------------------------------------- */
static int
chfs_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size)
{
return ENODEV;
}
/* --------------------------------------------------------------------- */
static int
chfs_start(struct mount *mp, int flags)
{
return 0;
}
/* --------------------------------------------------------------------- */
/* ARGSUSED2 */
static int
chfs_statvfs(struct mount *mp, struct statvfs *sbp)
{
struct chfs_mount *chmp;
struct ufsmount *ump;
dbg("statvfs\n");
ump = VFSTOUFS(mp);
chmp = ump->um_chfs;
sbp->f_flag = mp->mnt_flag;
sbp->f_bsize = chmp->chm_ebh->eb_size;
sbp->f_frsize = chmp->chm_ebh->eb_size;
sbp->f_iosize = chmp->chm_ebh->eb_size;
sbp->f_blocks = chmp->chm_ebh->peb_nr;
sbp->f_files = 0;
sbp->f_bavail = chmp->chm_nr_free_blocks - chmp->chm_resv_blocks_write;
#if 0
printf("chmp->chm_nr_free_blocks: %jd\n",
(intmax_t )chmp->chm_nr_free_blocks);
printf("chmp->chm_resv_blocks_write: %jd\n",
(intmax_t) chmp->chm_resv_blocks_write);
printf("chmp->chm_ebh->peb_nr: %jd\n",
(intmax_t) chmp->chm_ebh->peb_nr);
#endif
sbp->f_bfree = chmp->chm_nr_free_blocks;
sbp->f_bresvd = chmp->chm_resv_blocks_write;
/* FFS specific */
sbp->f_ffree = 0;
sbp->f_favail = 0;
sbp->f_fresvd = 0;
copy_statvfs_info(sbp, mp);
return 0;
}
/* --------------------------------------------------------------------- */
/* ARGSUSED0 */
static int
chfs_sync(struct mount *mp, int waitfor,
kauth_cred_t uc)
{
return 0;
}
/* --------------------------------------------------------------------- */
static void
chfs_init(void)
{
chfs_alloc_pool_caches();
chfs_ihashinit();
pool_init(&chfs_inode_pool, sizeof(struct chfs_inode), 0, 0, 0,
"chfsinopl", &pool_allocator_nointr, IPL_NONE);
ufs_init();
}
/* --------------------------------------------------------------------- */
static void
chfs_reinit(void)
{
chfs_ihashreinit();
ufs_reinit();
}
/* --------------------------------------------------------------------- */
static void
chfs_done(void)
{
ufs_done();
chfs_ihashdone();
pool_destroy(&chfs_inode_pool);
chfs_destroy_pool_caches();
}
/* --------------------------------------------------------------------- */
static int
chfs_snapshot(struct mount *mp, struct vnode *vp,
struct timespec *ctime)
{
return ENODEV;
}
/* --------------------------------------------------------------------- */
/*
* chfs vfs operations.
*/
extern const struct vnodeopv_desc chfs_fifoop_opv_desc;
extern const struct vnodeopv_desc chfs_specop_opv_desc;
extern const struct vnodeopv_desc chfs_vnodeop_opv_desc;
const struct vnodeopv_desc * const chfs_vnodeopv_descs[] = {
&chfs_fifoop_opv_desc,
&chfs_specop_opv_desc,
&chfs_vnodeop_opv_desc,
NULL,
};
struct vfsops chfs_vfsops = {
MOUNT_CHFS, /* vfs_name */
sizeof (struct chfs_args),
chfs_mount, /* vfs_mount */
chfs_start, /* vfs_start */
chfs_unmount, /* vfs_unmount */
chfs_root, /* vfs_root */
ufs_quotactl, /* vfs_quotactl */
chfs_statvfs, /* vfs_statvfs */
chfs_sync, /* vfs_sync */
chfs_vget, /* vfs_vget */
chfs_fhtovp, /* vfs_fhtovp */
chfs_vptofh, /* vfs_vptofh */
chfs_init, /* vfs_init */
chfs_reinit, /* vfs_reinit */
chfs_done, /* vfs_done */
NULL, /* vfs_mountroot */
chfs_snapshot, /* vfs_snapshot */
vfs_stdextattrctl, /* vfs_extattrctl */
(void *)eopnotsupp, /* vfs_suspendctl */
genfs_renamelock_enter,
genfs_renamelock_exit,
(void *)eopnotsupp,
chfs_vnodeopv_descs,
0, /* vfs_refcount */
{ NULL, NULL },
};
static int
chfs_modcmd(modcmd_t cmd, void *arg)
{
switch (cmd) {
case MODULE_CMD_INIT:
return vfs_attach(&chfs_vfsops);
case MODULE_CMD_FINI:
return vfs_detach(&chfs_vfsops);
default:
return ENOTTY;
}
}

393
sys/ufs/chfs/chfs_vnode.c Normal file
View File

@ -0,0 +1,393 @@
/* $NetBSD: chfs_vnode.c,v 1.1 2011/11/24 15:51:32 ahoka Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
* University of Szeged, Hungary
* Copyright (C) 2010 Tamas Toth <ttoth@inf.u-szeged.hu>
* Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* 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 "chfs.h"
#include "chfs_inode.h"
#include <sys/malloc.h>
#include <sys/kauth.h>
#include <sys/namei.h>
#include <sys/uio.h>
#include <sys/buf.h>
struct vnode *
chfs_vnode_lookup(struct chfs_mount *chmp, ino_t vno)
{
struct vnode *vp;
struct chfs_inode *ip;
TAILQ_FOREACH(vp, &chmp->chm_fsmp->mnt_vnodelist, v_mntvnodes) {
ip = VTOI(vp);
if (ip && ip->ino == vno)
return vp;
}
return NULL;
}
int
chfs_readvnode(struct mount* mp, ino_t ino, struct vnode** vpp)
{
struct ufsmount* ump = VFSTOUFS(mp);
struct chfs_mount *chmp = ump->um_chfs;
struct chfs_vnode_cache *chvc;
struct chfs_flash_vnode *chfvn;
struct chfs_inode *ip;
int err;
char* buf;
size_t retlen, len;
struct vnode* vp = NULL;
dbg("readvnode | ino: %llu\n", ino);
len = sizeof(struct chfs_flash_vnode);
KASSERT(vpp != NULL);
if (vpp != NULL) {
vp = *vpp;
}
ip = VTOI(vp);
chvc = ip->chvc;
if (chvc && ino != CHFS_ROOTINO) {
/* debug... */
printf("readvnode; offset: %" PRIu32 ", lnr: %d\n",
CHFS_GET_OFS(chvc->v->nref_offset), chvc->v->nref_lnr);
KASSERT((void *)chvc != (void *)chvc->v);
buf = kmem_alloc(len, KM_SLEEP);
err = chfs_read_leb(chmp, chvc->v->nref_lnr, buf,
CHFS_GET_OFS(chvc->v->nref_offset), len, &retlen);
if (err)
return err;
if (retlen != len) {
chfs_err("Error reading vnode: read: %zu insted of: %zu\n",
len, retlen);
return EIO;
}
chfvn = (struct chfs_flash_vnode*)buf;
chfs_set_vnode_size(vp, chfvn->dn_size);
ip->mode = chfvn->mode;
vp->v_type = IFTOVT(ip->mode);
ip->version = chfvn->version;
//ip->chvc->highest_version = ip->version;
ip->uid = chfvn->uid;
ip->gid = chfvn->gid;
ip->atime = chfvn->atime;
ip->mtime = chfvn->mtime;
ip->ctime = chfvn->ctime;
kmem_free(buf, len);
}
*vpp = vp;
return 0;
}
int
chfs_readdirent(struct mount *mp, struct chfs_node_ref *chnr, struct chfs_inode *pdir)
{
struct ufsmount *ump = VFSTOUFS(mp);
struct chfs_mount *chmp = ump->um_chfs;
struct chfs_flash_dirent_node chfdn;
struct chfs_dirent *fd;//, *pdents;
size_t len = sizeof(struct chfs_flash_dirent_node);
// struct chfs_vnode_cache* parent;
size_t retlen;
int err = 0;
// parent = chfs_get_vnode_cache(chmp, pdir->ino);
//read flash_dirent_node
err = chfs_read_leb(chmp, chnr->nref_lnr, (char *)&chfdn,
CHFS_GET_OFS(chnr->nref_offset), len, &retlen);
if (err) {
return err;
}
if (retlen != len) {
chfs_err("Error reading vnode: read: %zu insted of: %zu\n",
retlen, len);
return EIO;
}
//set fields of dirent
fd = chfs_alloc_dirent(chfdn.nsize + 1);
fd->version = chfdn.version;
fd->vno = chfdn.vno;
fd->type = chfdn.dtype;
fd->nsize = chfdn.nsize;
// fd->next = NULL;
err = chfs_read_leb(chmp, chnr->nref_lnr, fd->name,
CHFS_GET_OFS(chnr->nref_offset) + len, chfdn.nsize, &retlen);
if (err) {
return err;
}
if (retlen != chfdn.nsize) {
chfs_err("Error reading vnode: read: %zu insted of: %zu\n",
len, retlen);
return EIO;
}
fd->name[fd->nsize] = 0;
fd->nref = chnr;
chfs_add_fd_to_inode(chmp, pdir, fd);
/*
pdents = pdir->i_chfs_ext.dents;
if (!pdents)
pdir->i_chfs_ext.dents = fd;
else {
while (pdents->next != NULL) {
pdents = pdents->next;
}
pdents->next = fd;
}
*/
return 0;
}
/*
* Allocate a new inode.
*/
int
chfs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
struct componentname *cnp, int type)
{
struct chfs_inode *ip, *pdir;
struct vnode *vp;
struct ufsmount* ump = VFSTOUFS(dvp->v_mount);
struct chfs_mount* chmp = ump->um_chfs;
struct chfs_vnode_cache* chvc;
int error, ismember = 0;
ino_t vno;
struct chfs_dirent *nfd;//, *fd;
dbg("makeinode\n");
pdir = VTOI(dvp);
*vpp = NULL;
vno = ++(chmp->chm_max_vno);
error = VFS_VGET(dvp->v_mount, vno, &vp);
if (error)
return (error);
mutex_enter(&chmp->chm_lock_vnocache);
chvc = chfs_vnode_cache_get(chmp, vno);
mutex_exit(&chmp->chm_lock_vnocache);
chvc->pvno = pdir->ino;
chvc->vno_version = kmem_alloc(sizeof(uint64_t), KM_SLEEP);
*(chvc->vno_version) = 1;
if (type != VDIR)
chvc->nlink = 1;
else
chvc->nlink = 2;
// chfs_vnode_cache_set_state(chmp, chvc, VNO_STATE_CHECKEDABSENT);
chvc->state = VNO_STATE_CHECKEDABSENT;
ip = VTOI(vp);
ip->ino = vno;
if (type == VDIR)
chfs_set_vnode_size(vp, 512);
else
chfs_set_vnode_size(vp, 0);
ip->uid = kauth_cred_geteuid(cnp->cn_cred);
ip->gid = kauth_cred_getegid(cnp->cn_cred);
ip->version = 1;
ip->iflag |= (IN_ACCESS | IN_CHANGE | IN_UPDATE);
ip->chvc = chvc;
//ip->chvc->highest_version = 1;
ip->target = NULL;
ip->mode = mode;
vp->v_type = type; /* Rest init'd in getnewvnode(). */
if ((ip->mode & ISGID) && (kauth_cred_ismember_gid(cnp->cn_cred,
ip->gid, &ismember) != 0 || !ismember) &&
kauth_authorize_generic(cnp->cn_cred, KAUTH_GENERIC_ISSUSER, NULL))
ip->mode &= ~ISGID;
chfs_update(vp, NULL, NULL, UPDATE_WAIT);
mutex_enter(&chmp->chm_lock_mountfields);
//write inode to flash
error = chfs_write_flash_vnode(chmp, ip, ALLOC_NORMAL);
if (error) {
mutex_exit(&chmp->chm_lock_mountfields);
vput(vp);
vput(dvp);
return error;
}
//update parent directory and write it to the flash
pdir->iflag |= (IN_ACCESS | IN_CHANGE | IN_MODIFY | IN_UPDATE);
chfs_update(dvp, NULL, NULL, UPDATE_WAIT);
error = chfs_write_flash_vnode(chmp, pdir, ALLOC_NORMAL);
if (error) {
mutex_exit(&chmp->chm_lock_mountfields);
vput(vp);
vput(dvp);
return error;
}
vput(dvp);
//set up node's full dirent
nfd = chfs_alloc_dirent(cnp->cn_namelen + 1);
nfd->vno = ip->ino;
nfd->version = (++pdir->chvc->highest_version);
nfd->type = type;
// nfd->next = NULL;
nfd->nsize = cnp->cn_namelen;
memcpy(&(nfd->name), cnp->cn_nameptr, cnp->cn_namelen);
nfd->name[nfd->nsize] = 0;
nfd->nhash = hash32_buf(nfd->name, cnp->cn_namelen, HASH32_BUF_INIT);
// write out direntry
error = chfs_write_flash_dirent(chmp, pdir, ip, nfd, ip->ino, ALLOC_NORMAL);
if (error) {
mutex_exit(&chmp->chm_lock_mountfields);
vput(vp);
return error;
}
//TODO set parent's dir times
chfs_add_fd_to_inode(chmp, pdir, nfd);
/*
fd = pdir->i_chfs_ext.dents;
if (!fd)
pdir->i_chfs_ext.dents = nfd;
else {
while (fd->next != NULL) {
fd = fd->next;
}
fd->next = nfd;
}
*/
//pdir->i_nlink++;
pdir->chvc->nlink++;
mutex_exit(&chmp->chm_lock_mountfields);
*vpp = vp;
return (0);
}
void
chfs_set_vnode_size(struct vnode *vp, size_t size)
{
struct chfs_inode *ip;
KASSERT(vp != NULL);
ip = VTOI(vp);
KASSERT(ip != NULL);
ip->size = size;
vp->v_size = vp->v_writesize = size;
return;
}
void
chfs_change_size_free(struct chfs_mount *chmp,
struct chfs_eraseblock *cheb, int change)
{
KASSERT(mutex_owned(&chmp->chm_lock_sizes));
KASSERT((int)(chmp->chm_free_size + change) >= 0);
KASSERT((int)(cheb->free_size + change) >= 0);
KASSERT((int)(cheb->free_size + change) <= chmp->chm_ebh->eb_size);
chmp->chm_free_size += change;
cheb->free_size += change;
return;
}
void
chfs_change_size_dirty(struct chfs_mount *chmp,
struct chfs_eraseblock *cheb, int change)
{
KASSERT(mutex_owned(&chmp->chm_lock_sizes));
KASSERT((int)(chmp->chm_dirty_size + change) >= 0);
KASSERT((int)(cheb->dirty_size + change) >= 0);
KASSERT((int)(cheb->dirty_size + change) <= chmp->chm_ebh->eb_size);
chmp->chm_dirty_size += change;
cheb->dirty_size += change;
return;
}
void
chfs_change_size_unchecked(struct chfs_mount *chmp,
struct chfs_eraseblock *cheb, int change)
{
KASSERT(mutex_owned(&chmp->chm_lock_sizes));
KASSERT((int)(chmp->chm_unchecked_size + change) >= 0);
KASSERT((int)(cheb->unchecked_size + change) >= 0);
KASSERT((int)(cheb->unchecked_size + change) <= chmp->chm_ebh->eb_size);
chmp->chm_unchecked_size += change;
cheb->unchecked_size += change;
return;
}
void
chfs_change_size_used(struct chfs_mount *chmp,
struct chfs_eraseblock *cheb, int change)
{
KASSERT(mutex_owned(&chmp->chm_lock_sizes));
KASSERT((int)(chmp->chm_used_size + change) >= 0);
KASSERT((int)(cheb->used_size + change) >= 0);
KASSERT((int)(cheb->used_size + change) <= chmp->chm_ebh->eb_size);
chmp->chm_used_size += change;
cheb->used_size += change;
return;
}
void
chfs_change_size_wasted(struct chfs_mount *chmp,
struct chfs_eraseblock *cheb, int change)
{
KASSERT(mutex_owned(&chmp->chm_lock_sizes));
KASSERT((int)(chmp->chm_wasted_size + change) >= 0);
KASSERT((int)(cheb->wasted_size + change) >= 0);
KASSERT((int)(cheb->wasted_size + change) <= chmp->chm_ebh->eb_size);
chmp->chm_wasted_size += change;
cheb->wasted_size += change;
return;
}

View File

@ -0,0 +1,165 @@
/* $NetBSD: chfs_vnode_cache.c,v 1.1 2011/11/24 15:51:32 ahoka Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
* University of Szeged, Hungary
* Copyright (C) 2010 Tamas Toth <ttoth@inf.u-szeged.hu>
* Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* 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 "chfs.h"
#include <sys/pool.h>
struct chfs_vnode_cache **
chfs_vnocache_hash_init(void)
{
return kmem_zalloc(VNODECACHE_SIZE *
sizeof(struct chfs_vnode_cache *), KM_SLEEP);
}
/**
* chfs_set_vnode_cache_state - set state of a vnode_cache
* @chmp: fs super block info
* @vc: vnode_cache
* @state: new state
*/
void
chfs_vnode_cache_set_state(struct chfs_mount *chmp,
struct chfs_vnode_cache* vc, int state)
{
/* XXX do we really need locking here? */
KASSERT(mutex_owned(&chmp->chm_lock_vnocache));
vc->state = state;
}
/**
* chfs_get_vnode_cache - get a vnode_cache from the vnocache_hash
* @chmp: fs super block info
* @ino: inode for search
* Returns the vnode_cache.
*/
struct chfs_vnode_cache *
chfs_vnode_cache_get(struct chfs_mount *chmp, ino_t vno)
{
struct chfs_vnode_cache* ret;
KASSERT(mutex_owned(&chmp->chm_lock_vnocache));
ret = chmp->chm_vnocache_hash[vno % VNODECACHE_SIZE];
if (ret == NULL) {
return NULL;
}
while (ret && ret->vno < vno) {
ret = ret->next;
}
if (ret && ret->vno != vno) {
ret = NULL;
}
return ret;
}
/**
* chfs_add_vnode_cache - add a vnode_cache to the vnocache_hash
* @chmp: fs super block info
* @new: new vnode_cache
*/
void
chfs_vnode_cache_add(struct chfs_mount *chmp,
struct chfs_vnode_cache* new)
{
struct chfs_vnode_cache** prev;
KASSERT(mutex_owned(&chmp->chm_lock_vnocache));
if (!new->vno) {
new->vno = ++chmp->chm_max_vno;
}
prev = &chmp->chm_vnocache_hash[new->vno % VNODECACHE_SIZE];
while ((*prev) && (*prev)->vno < new->vno) {
prev = &((*prev)->next);
}
new->next = *prev;
*prev = new;
}
/**
* chfs_del_vnode_cache - del a vnode_cache from the vnocache_hash
* @chmp: fs super block info
* @old: old vnode_cache
*/
void
chfs_vnode_cache_remove(struct chfs_mount *chmp,
struct chfs_vnode_cache* old)
{
struct chfs_vnode_cache** prev;
KASSERT(mutex_owned(&chmp->chm_lock_vnocache));
prev = &chmp->chm_vnocache_hash[old->vno % VNODECACHE_SIZE];
while ((*prev) && (*prev)->vno < old->vno) {
prev = &(*prev)->next;
}
if ((*prev) == old) {
*prev = old->next;
}
if (old->state != VNO_STATE_READING &&
old->state != VNO_STATE_CLEARING) {
chfs_vnode_cache_free(old);
}
}
/**
* chfs_free_vnode_caches - free the vnocache_hash
* @chmp: fs super block info
*/
void
chfs_vnocache_hash_destroy(struct chfs_vnode_cache **hash)
{
struct chfs_vnode_cache *this, *next;
int i;
for (i = 0; i < VNODECACHE_SIZE; i++) {
this = hash[i];
while (this) {
next = this->next;
chfs_vnode_cache_free(this);
this = next;
}
hash[i] = NULL;
}
}

1764
sys/ufs/chfs/chfs_vnops.c Normal file

File diff suppressed because it is too large Load Diff

258
sys/ufs/chfs/chfs_wbuf.c Normal file
View File

@ -0,0 +1,258 @@
/* $NetBSD: chfs_wbuf.c,v 1.1 2011/11/24 15:51:32 ahoka Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
* University of Szeged, Hungary
* Copyright (C) 2010 Tamas Toth <ttoth@inf.u-szeged.hu>
* Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* 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 <dev/flash/flash.h>
#include <sys/uio.h>
#include "chfs.h"
//#include </root/xipffs/netbsd.chfs/chfs.h>
#define DBG_WBUF 1
#define PAD(x) (((x)+3)&~3)
#define EB_ADDRESS(x) ( ((unsigned long)(x) / chmp->chm_ebh->eb_size) * chmp->chm_ebh->eb_size )
#define PAGE_DIV(x) ( ((unsigned long)(x) / (unsigned long)(chmp->chm_wbuf_pagesize)) * (unsigned long)(chmp->chm_wbuf_pagesize) )
#define PAGE_MOD(x) ( (unsigned long)(x) % (unsigned long)(chmp->chm_wbuf_pagesize) )
/*
// test functions
int wbuf_test(void);
void wbuf_test_erase_flash(struct chfs_mount*);
void wbuf_test_callback(struct erase_instruction*);
*/
#define NOPAD 0
#define SETPAD 1
/**
* chfs_flush_wbuf - write wbuf to the flash
* @chmp: super block info
* @pad: padding (NOPAD / SETPAD)
* Returns zero in case of success.
*/
static int
chfs_flush_wbuf(struct chfs_mount *chmp, int pad)
{
int ret=0;
size_t retlen = 0;
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
KASSERT(mutex_owned(&chmp->chm_lock_sizes));
KASSERT(rw_write_held(&chmp->chm_lock_wbuf));
if (pad) {
chmp->chm_wbuf_len = PAD(chmp->chm_wbuf_len);
memset(chmp->chm_wbuf + chmp->chm_wbuf_len, 0, chmp->chm_wbuf_pagesize - chmp->chm_wbuf_len);
struct chfs_flash_padding_node* padnode = (void*)(chmp->chm_wbuf + chmp->chm_wbuf_len);
padnode->magic = htole16(CHFS_FS_MAGIC_BITMASK);
padnode->type = htole16(CHFS_NODETYPE_PADDING);
padnode->length = htole32(chmp->chm_wbuf_pagesize - chmp->chm_wbuf_len);
padnode->hdr_crc = htole32(crc32(0, (uint8_t *)padnode, sizeof(*padnode)-4));
struct chfs_node_ref *nref;
nref = chfs_alloc_node_ref(chmp->chm_nextblock);
nref->nref_offset = chmp->chm_wbuf_ofs + chmp->chm_wbuf_len;
nref->nref_offset = CHFS_GET_OFS(nref->nref_offset) |
CHFS_OBSOLETE_NODE_MASK;
chmp->chm_wbuf_len = chmp->chm_wbuf_pagesize;
chfs_change_size_free(chmp, chmp->chm_nextblock, -padnode->length);
chfs_change_size_wasted(chmp, chmp->chm_nextblock, padnode->length);
}
ret = chfs_write_leb(chmp, chmp->chm_nextblock->lnr, chmp->chm_wbuf, chmp->chm_wbuf_ofs, chmp->chm_wbuf_len, &retlen);
if(ret) {
return ret;
}
memset(chmp->chm_wbuf,0xff,chmp->chm_wbuf_pagesize);
chmp->chm_wbuf_ofs += chmp->chm_wbuf_pagesize;
chmp->chm_wbuf_len = 0;
return 0;
}
/**
* chfs_fill_wbuf - write to wbuf
* @chmp: super block info
* @buf: buffer
* @len: buffer length
* Return the len of the buf what we didn't write to the wbuf.
*/
static size_t
chfs_fill_wbuf(struct chfs_mount *chmp, const u_char *buf, size_t len)
{
if (len && !chmp->chm_wbuf_len && (len >= chmp->chm_wbuf_pagesize)) {
return 0;
}
if (len > (chmp->chm_wbuf_pagesize - chmp->chm_wbuf_len)) {
len = chmp->chm_wbuf_pagesize - chmp->chm_wbuf_len;
}
memcpy(chmp->chm_wbuf + chmp->chm_wbuf_len, buf, len);
chmp->chm_wbuf_len += (int) len;
return len;
}
/**
* chfs_write_wbuf - write to wbuf and then the flash
* @chmp: super block info
* @invecs: io vectors
* @count: num of vectors
* @to: offset of target
* @retlen: writed bytes
* Returns zero in case of success.
*/
int
chfs_write_wbuf(struct chfs_mount* chmp, const struct iovec *invecs, long count,
off_t to, size_t *retlen)
{
int invec, ret = 0;
size_t wbuf_retlen, donelen = 0;
int outvec_to = to;
int lnr = chmp->chm_nextblock->lnr;
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
KASSERT(mutex_owned(&chmp->chm_lock_sizes));
KASSERT(!rw_write_held(&chmp->chm_lock_wbuf));
rw_enter(&chmp->chm_lock_wbuf, RW_WRITER);
//dbg("1. wbuf ofs: %zu, len: %zu\n", chmp->chm_wbuf_ofs, chmp->chm_wbuf_len);
if (chmp->chm_wbuf_ofs == 0xffffffff) {
chmp->chm_wbuf_ofs = PAGE_DIV(to);
chmp->chm_wbuf_len = PAGE_MOD(to);
memset(chmp->chm_wbuf, 0xff, chmp->chm_wbuf_pagesize);
}
//dbg("2. wbuf ofs: %zu, len: %zu\n", chmp->chm_wbuf_ofs, chmp->chm_wbuf_len);
if (EB_ADDRESS(to) != EB_ADDRESS(chmp->chm_wbuf_ofs)) {
if (chmp->chm_wbuf_len) {
ret = chfs_flush_wbuf(chmp, SETPAD);
if (ret)
goto outerr;
}
chmp->chm_wbuf_ofs = PAGE_DIV(to);
chmp->chm_wbuf_len = PAGE_MOD(to);
}
//dbg("3. wbuf ofs: %zu, len: %zu\n", chmp->chm_wbuf_ofs, chmp->chm_wbuf_len);
if (to != PAD(chmp->chm_wbuf_ofs + chmp->chm_wbuf_len)) {
dbg("to: %llu != %zu\n", to, PAD(chmp->chm_wbuf_ofs + chmp->chm_wbuf_len));
dbg("Non-contiguous write\n");
panic("BUG\n");
}
/* adjust alignment offset */
if (chmp->chm_wbuf_len != PAGE_MOD(to)) {
chmp->chm_wbuf_len = PAGE_MOD(to);
/* take care of alignement to next page*/
if (!chmp->chm_wbuf_len) {
chmp->chm_wbuf_len += chmp->chm_wbuf_pagesize;
ret = chfs_flush_wbuf(chmp, NOPAD);
if (ret)
goto outerr;
}
}
for (invec = 0; invec < count; invec++) {
int vlen = invecs[invec].iov_len;
u_char* v = invecs[invec].iov_base;
//dbg("invec:%d len:%d\n", invec, vlen);
wbuf_retlen = chfs_fill_wbuf(chmp, v, vlen);
if (chmp->chm_wbuf_len == chmp->chm_wbuf_pagesize) {
ret = chfs_flush_wbuf(chmp, NOPAD);
if (ret) {
goto outerr;
}
}
vlen -= wbuf_retlen;
outvec_to += wbuf_retlen;
v += wbuf_retlen;
donelen += wbuf_retlen;
if (vlen >= chmp->chm_wbuf_pagesize) {
ret = chfs_write_leb(chmp, lnr, v, outvec_to, PAGE_DIV(vlen), &wbuf_retlen);
//dbg("fd->write: %zu\n", wbuf_retlen);
vlen -= wbuf_retlen;
outvec_to += wbuf_retlen;
chmp->chm_wbuf_ofs = outvec_to;
v += wbuf_retlen;
donelen += wbuf_retlen;
}
wbuf_retlen = chfs_fill_wbuf(chmp, v, vlen);
if (chmp->chm_wbuf_len == chmp->chm_wbuf_pagesize) {
ret = chfs_flush_wbuf(chmp, NOPAD);
if (ret)
goto outerr;
}
// if we write the last vector, we flush with padding
/*if (invec == count-1) {
ret = chfs_flush_wbuf(chmp, SETPAD);
if (ret)
goto outerr;
}*/
outvec_to += wbuf_retlen;
donelen += wbuf_retlen;
}
*retlen = donelen;
rw_exit(&chmp->chm_lock_wbuf);
return ret;
outerr:
*retlen = 0;
return ret;
}
int chfs_flush_pending_wbuf(struct chfs_mount *chmp)
{
//dbg("flush pending wbuf\n");
int err;
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
mutex_enter(&chmp->chm_lock_sizes);
rw_enter(&chmp->chm_lock_wbuf, RW_WRITER);
err = chfs_flush_wbuf(chmp, SETPAD);
rw_exit(&chmp->chm_lock_wbuf);
mutex_exit(&chmp->chm_lock_sizes);
return err;
}

544
sys/ufs/chfs/chfs_write.c Normal file
View File

@ -0,0 +1,544 @@
/* $NetBSD: chfs_write.c,v 1.1 2011/11/24 15:51:32 ahoka Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
* University of Szeged, Hungary
* Copyright (C) 2010 David Tengeri <dtengeri@inf.u-szeged.hu>
* Copyright (C) 2010 Tamas Toth <ttoth@inf.u-szeged.hu>
* Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* 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.
*/
/*
* chfs_write.c
*
* Created on: 2010.02.17.
* Author: dtengeri
*/
#include <sys/param.h>
#include <sys/buf.h>
#include "chfs.h"
int
chfs_write_flash_vnode(struct chfs_mount *chmp,
struct chfs_inode *ip, int prio)
{
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
struct chfs_flash_vnode *fvnode;
struct chfs_vnode_cache* chvc;
struct chfs_node_ref *nref;
struct iovec vec;
size_t size, retlen;
int err = 0, retries = 0;
if (ip->ino == CHFS_ROOTINO)
return 0;
fvnode = chfs_alloc_flash_vnode();
if (!fvnode)
return ENOMEM;
chvc = ip->chvc;
/* setting up flash_vnode members */
size = sizeof(*fvnode);
//dbg("size: %zu | PADDED: %zu\n", size, CHFS_PAD(size));
fvnode->magic = htole16(CHFS_FS_MAGIC_BITMASK);
fvnode->type = htole16(CHFS_NODETYPE_VNODE);
fvnode->length = htole32(CHFS_PAD(size));
fvnode->hdr_crc = htole32(crc32(0, (uint8_t *)fvnode,
CHFS_NODE_HDR_SIZE - 4));
fvnode->vno = htole64(ip->ino);
fvnode->version = htole64(++ip->chvc->highest_version);
fvnode->mode = htole32(ip->mode);
fvnode->dn_size = htole32(ip->size);
fvnode->atime = htole32(ip->atime);
fvnode->ctime = htole32(ip->ctime);
fvnode->mtime = htole32(ip->mtime);
fvnode->gid = htole32(ip->gid);
fvnode->uid = htole32(ip->uid);
fvnode->node_crc = htole32(crc32(0, (uint8_t *)fvnode, size - 4));
/* write out flash_vnode */
retry:
if (prio == ALLOC_GC) {
/* the GC calls this function */
err = chfs_reserve_space_gc(chmp, CHFS_PAD(size));
if (err)
goto out;
} else {
chfs_gc_trigger(chmp);
if (prio == ALLOC_NORMAL)
err = chfs_reserve_space_normal(chmp,
CHFS_PAD(size), ALLOC_NORMAL);
else
err = chfs_reserve_space_normal(chmp,
CHFS_PAD(size), ALLOC_DELETION);
if (err)
goto out;
}
nref = chfs_alloc_node_ref(chmp->chm_nextblock);
if (!nref) {
err = ENOMEM;
goto out;
}
mutex_enter(&chmp->chm_lock_sizes);
nref->nref_offset = chmp->chm_ebh->eb_size - chmp->chm_nextblock->free_size;
chfs_change_size_free(chmp, chmp->chm_nextblock, -CHFS_PAD(size));
vec.iov_base = fvnode;
vec.iov_len = CHFS_PAD(size);
err = chfs_write_wbuf(chmp, &vec, 1, nref->nref_offset, &retlen);
if (err || retlen != CHFS_PAD(size)) {
chfs_err("error while writing out flash vnode to the media\n");
chfs_err("err: %d | size: %zu | retlen : %zu\n",
err, CHFS_PAD(size), retlen);
chfs_change_size_dirty(chmp,
chmp->chm_nextblock, CHFS_PAD(size));
if (retries) {
err = EIO;
mutex_exit(&chmp->chm_lock_sizes);
goto out;
}
retries++;
mutex_exit(&chmp->chm_lock_sizes);
goto retry;
}
//Everything went well
chfs_change_size_used(chmp,
&chmp->chm_blocks[nref->nref_lnr], CHFS_PAD(size));
mutex_exit(&chmp->chm_lock_sizes);
chfs_add_vnode_ref_to_vc(chmp, chvc, nref);
KASSERT(chmp->chm_blocks[nref->nref_lnr].used_size <= chmp->chm_ebh->eb_size);
out:
chfs_free_flash_vnode(fvnode);
return err;
}
int
chfs_write_flash_dirent(struct chfs_mount *chmp, struct chfs_inode *pdir,
struct chfs_inode *ip, struct chfs_dirent *fd,
ino_t ino, int prio)
{
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
struct chfs_flash_dirent_node *fdirent;
struct chfs_node_ref *nref;
struct iovec vec[2];
size_t size, retlen;
int err = 0, retries = 0;
uint8_t *name;
size_t namelen;
KASSERT(fd->vno != CHFS_ROOTINO);
fdirent = chfs_alloc_flash_dirent();
if (!fdirent)
return ENOMEM;
size = sizeof(*fdirent) + fd->nsize;
namelen = CHFS_PAD(size) - sizeof(*fdirent);
name = kmem_zalloc(namelen, KM_SLEEP);
memcpy(name, fd->name, fd->nsize);
//dbg("namelen: %zu | nsize: %hhu\n", namelen, fd->nsize);
//dbg("size: %zu | PADDED: %zu\n", size, CHFS_PAD(size));
fdirent->magic = htole16(CHFS_FS_MAGIC_BITMASK);
fdirent->type = htole16(CHFS_NODETYPE_DIRENT);
fdirent->length = htole32(CHFS_PAD(size));
fdirent->hdr_crc = htole32(crc32(0, (uint8_t *)fdirent,
CHFS_NODE_HDR_SIZE - 4));
fdirent->vno = htole64(ino);
fdirent->pvno = htole64(pdir->ino);
fdirent->version = htole64(++pdir->chvc->highest_version);
fdirent->mctime = ip?ip->ctime:0;
fdirent->nsize = fd->nsize;
fdirent->dtype = fd->type;
fdirent->name_crc = crc32(0, (uint8_t *)&(fd->name), fd->nsize);
fdirent->node_crc = crc32(0, (uint8_t *)fdirent, sizeof(*fdirent) - 4);
vec[0].iov_base = fdirent;
vec[0].iov_len = sizeof(*fdirent);
vec[1].iov_base = name;
vec[1].iov_len = namelen;
retry:
if (prio == ALLOC_GC) {
/* the GC calls this function */
err = chfs_reserve_space_gc(chmp, CHFS_PAD(size));
if (err)
goto out;
} else {
chfs_gc_trigger(chmp);
if (prio == ALLOC_NORMAL)
err = chfs_reserve_space_normal(chmp,
CHFS_PAD(size), ALLOC_NORMAL);
else
err = chfs_reserve_space_normal(chmp,
CHFS_PAD(size), ALLOC_DELETION);
if (err)
goto out;
}
nref = chfs_alloc_node_ref(chmp->chm_nextblock);
if (!nref) {
err = ENOMEM;
goto out;
}
mutex_enter(&chmp->chm_lock_sizes);
nref->nref_offset = chmp->chm_ebh->eb_size - chmp->chm_nextblock->free_size;
chfs_change_size_free(chmp, chmp->chm_nextblock, -CHFS_PAD(size));
err = chfs_write_wbuf(chmp, vec, 2, nref->nref_offset, &retlen);
if (err || retlen != CHFS_PAD(size)) {
chfs_err("error while writing out flash dirent node to the media\n");
chfs_err("err: %d | size: %zu | retlen : %zu\n",
err, CHFS_PAD(size), retlen);
chfs_change_size_dirty(chmp,
chmp->chm_nextblock, CHFS_PAD(size));
if (retries) {
err = EIO;
mutex_exit(&chmp->chm_lock_sizes);
goto out;
}
retries++;
mutex_exit(&chmp->chm_lock_sizes);
goto retry;
}
// Everything went well
chfs_change_size_used(chmp,
&chmp->chm_blocks[nref->nref_lnr], CHFS_PAD(size));
mutex_exit(&chmp->chm_lock_sizes);
KASSERT(chmp->chm_blocks[nref->nref_lnr].used_size <= chmp->chm_ebh->eb_size);
fd->nref = nref;
if (prio != ALLOC_DELETION) {
chfs_add_node_to_list(chmp,
pdir->chvc, nref, &pdir->chvc->dirents);
}
out:
chfs_free_flash_dirent(fdirent);
return err;
}
/**
* chfs_write_flash_dnode - write out a data node to flash
* @chmp: chfs mount structure
* @vp: vnode where the data belongs to
* @bp: buffer contains data
*/
int
chfs_write_flash_dnode(struct chfs_mount *chmp, struct vnode *vp,
struct buf *bp, struct chfs_full_dnode *fd)
{
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
int err = 0, retries = 0;
size_t size, retlen;
off_t ofs;
struct chfs_flash_data_node *dnode;
struct chfs_node_ref *nref;
struct chfs_inode *ip = VTOI(vp);
struct iovec vec[2];
uint32_t len;
void *tmpbuf = NULL;
KASSERT(ip->ino != CHFS_ROOTINO);
dnode = chfs_alloc_flash_dnode();
if (!dnode)
return ENOMEM;
/* initialize flash data node */
ofs = bp->b_blkno * PAGE_SIZE;
//dbg("vp->v_size: %ju, bp->b_blkno: %ju, bp-b_data: %p,"
// " bp->b_resid: %ju\n",
// (uintmax_t )vp->v_size, (uintmax_t )bp->b_blkno,
// bp->b_data, (uintmax_t )bp->b_resid);
//dbg("[XXX]vp->v_size - ofs: %llu\n", (vp->v_size - ofs));
len = MIN((vp->v_size - ofs), bp->b_resid);
size = sizeof(*dnode) + len;
dnode->magic = htole16(CHFS_FS_MAGIC_BITMASK);
dnode->type = htole16(CHFS_NODETYPE_DATA);
dnode->length = htole32(CHFS_PAD(size));
dnode->hdr_crc = htole32(crc32(0, (uint8_t *)dnode,
CHFS_NODE_HDR_SIZE - 4));
dnode->vno = htole64(ip->ino);
dnode->version = htole64(++ip->chvc->highest_version);
dnode->offset = htole64(ofs);
dnode->data_length = htole32(len);
dnode->data_crc = htole32(crc32(0, (uint8_t *)bp->b_data, len));
dnode->node_crc = htole32(crc32(0, (uint8_t *)dnode,
sizeof(*dnode) - 4));
dbg("dnode @%llu %ub v%llu\n", dnode->offset, dnode->data_length, dnode->version);
if (CHFS_PAD(size) - sizeof(*dnode)) {
tmpbuf = kmem_zalloc(CHFS_PAD(size)
- sizeof(*dnode), KM_SLEEP);
memcpy(tmpbuf, bp->b_data, len);
}
/* creating iovecs for wbuf */
vec[0].iov_base = dnode;
vec[0].iov_len = sizeof(*dnode);
vec[1].iov_base = tmpbuf;
vec[1].iov_len = CHFS_PAD(size) - sizeof(*dnode);
fd->frags = 0;
fd->ofs = ofs;
fd->size = len;
retry:
/* Reserve space for data node. This will set up the next eraseblock
* where to we will write.
*/
chfs_gc_trigger(chmp);
err = chfs_reserve_space_normal(chmp,
CHFS_PAD(size), ALLOC_NORMAL);
if (err)
goto out;
nref = chfs_alloc_node_ref(chmp->chm_nextblock);
if (!nref) {
err = ENOMEM;
goto out;
}
nref->nref_offset =
chmp->chm_ebh->eb_size - chmp->chm_nextblock->free_size;
KASSERT(nref->nref_offset < chmp->chm_ebh->eb_size);
mutex_enter(&chmp->chm_lock_sizes);
chfs_change_size_free(chmp,
chmp->chm_nextblock, -CHFS_PAD(size));
//dbg("vno: %llu nref lnr: %u offset: %u\n",
// dnode->vno, nref->nref_lnr, nref->nref_offset);
err = chfs_write_wbuf(chmp, vec, 2, nref->nref_offset, &retlen);
if (err || retlen != CHFS_PAD(size)) {
chfs_err("error while writing out flash data node to the media\n");
chfs_err("err: %d | size: %zu | retlen : %zu\n",
err, size, retlen);
chfs_change_size_dirty(chmp,
chmp->chm_nextblock, CHFS_PAD(size));
if (retries) {
err = EIO;
mutex_exit(&chmp->chm_lock_sizes);
goto out;
}
retries++;
mutex_exit(&chmp->chm_lock_sizes);
goto retry;
}
/* Everything went well */
ip->write_size += fd->size;
chfs_change_size_used(chmp,
&chmp->chm_blocks[nref->nref_lnr], CHFS_PAD(size));
mutex_exit(&chmp->chm_lock_sizes);
KASSERT(chmp->chm_blocks[nref->nref_lnr].used_size <= chmp->chm_ebh->eb_size);
fd->nref = nref;
chfs_add_node_to_list(chmp, ip->chvc, nref, &ip->chvc->dnode);
out:
chfs_free_flash_dnode(dnode);
if (CHFS_PAD(size) - sizeof(*dnode)) {
kmem_free(tmpbuf, CHFS_PAD(size) - sizeof(*dnode));
}
return err;
}
/**
* chfs_do_link - makes a copy from a node
* @old: old node
* @oldfd: dirent of old node
* @parent: parent of new node
* @name: name of new node
* @namelen: length of name
* This function writes the dirent of the new node to the media.
*/
int
chfs_do_link(struct chfs_inode *ip, struct chfs_inode *parent, const char *name, int namelen, enum vtype type)
{
int error = 0;
struct vnode *vp = ITOV(ip);
struct ufsmount *ump = VFSTOUFS(vp->v_mount);
struct chfs_mount *chmp = ump->um_chfs;
struct chfs_dirent *newfd = NULL;
// struct chfs_dirent *fd = NULL;
//dbg("link vno: %llu\n", ip->ino);
newfd = chfs_alloc_dirent(namelen + 1);
newfd->vno = ip->ino;
newfd->type = type;
newfd->nsize = namelen;
memcpy(newfd->name, name, namelen);
newfd->name[newfd->nsize] = 0;
// newfd->next = NULL;
ip->chvc->nlink++;
parent->chvc->nlink++;
ip->iflag |= IN_CHANGE;
chfs_update(vp, NULL, NULL, UPDATE_WAIT);
mutex_enter(&chmp->chm_lock_mountfields);
error = chfs_write_flash_vnode(chmp, ip, ALLOC_NORMAL);
if (error)
return error;
error = chfs_write_flash_dirent(chmp,
parent, ip, newfd, ip->ino, ALLOC_NORMAL);
/* TODO: what should we do if error isn't zero? */
mutex_exit(&chmp->chm_lock_mountfields);
/* add fd to the fd list */
TAILQ_INSERT_TAIL(&parent->dents, newfd, fds);
#if 0
fd = parent->dents;
if (!fd) {
parent->dents = newfd;
} else {
while (fd->next)
fd = fd->next;
fd->next = newfd;
}
#endif
return error;
}
/**
* chfs_do_unlink - delete a node
* @ip: node what we'd like to delete
* @parent: parent of the node
* @name: name of the node
* @namelen: length of name
* This function set the nlink and vno of the node zero and write its dirent to the media.
*/
int
chfs_do_unlink(struct chfs_inode *ip,
struct chfs_inode *parent, const char *name, int namelen)
{
struct chfs_dirent *fd, *tmpfd;
int error = 0;
struct vnode *vp = ITOV(ip);
struct ufsmount *ump = VFSTOUFS(vp->v_mount);
struct chfs_mount *chmp = ump->um_chfs;
struct chfs_node_ref *nref;
//dbg("unlink vno: %llu\n", ip->ino);
vflushbuf(vp, 0);
mutex_enter(&chmp->chm_lock_mountfields);
/* remove the full direntry from the parent dents list */
TAILQ_FOREACH_SAFE(fd, &parent->dents, fds, tmpfd) {
if (fd->vno == ip->ino &&
fd->nsize == namelen &&
!memcmp(fd->name, name, fd->nsize)) {
if (fd->type == VDIR && ip->chvc->nlink == 2)
ip->chvc->nlink = 0;
else
ip->chvc->nlink--;
fd->type = VNON;
TAILQ_REMOVE(&parent->dents, fd, fds);
/* remove nref from dirents list */
nref = parent->chvc->dirents;
if (nref == fd->nref) {
nref->nref_next = fd->nref->nref_next;
} else {
while (nref->nref_next && nref->nref_next != fd->nref)
nref = nref->nref_next;
if (nref->nref_next)
nref->nref_next = fd->nref->nref_next;
}
//dbg("FD->NREF vno: %llu, lnr: %u, ofs: %u\n",
// fd->vno, fd->nref->nref_lnr, fd->nref->nref_offset);
chfs_mark_node_obsolete(chmp, fd->nref);
error = chfs_write_flash_dirent(chmp,
parent, ip, fd, 0, ALLOC_DELETION);
//dbg("FD->NREF vno: %llu, lnr: %u, ofs: %u\n",
// fd->vno, fd->nref->nref_lnr, fd->nref->nref_offset);
chfs_mark_node_obsolete(chmp, fd->nref);
nref = ip->chvc->dnode;
while (nref != (struct chfs_node_ref *)ip->chvc) {
//dbg("DATA NREF\n");
chfs_mark_node_obsolete(chmp, nref);
nref = nref->nref_next;
}
ip->chvc->dnode = (struct chfs_node_ref *)ip->chvc;
nref = ip->chvc->v;
while (nref != (struct chfs_node_ref *)ip->chvc) {
//dbg("V NREF\n");
chfs_mark_node_obsolete(chmp, nref);
nref = nref->nref_next;
}
ip->chvc->v = ip->chvc->v->nref_next;
parent->chvc->nlink--;
//TODO: if error
}
}
mutex_exit(&chmp->chm_lock_mountfields);
return error;
}

48
sys/ufs/chfs/debug.c Normal file
View File

@ -0,0 +1,48 @@
/* $NetBSD: debug.c,v 1.1 2011/11/24 15:51:32 ahoka Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
* University of Szeged, Hungary
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* 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.
*/
/*
* XipFFS -- Xip Flash File System
*
* Copyright (C) 2009 Ferenc Havasi <havasi@inf.u-szeged.hu>,
* Zoltan Sogor <weth@inf.u-szeged.hu>,
* ...
* University of Szeged, Hungary
*
*
* For licensing information, see the file 'LICENCE' in this directory.
*
*/
#include "chfs.h"
//#include </root/xipffs/netbsd.chfs/chfs.h>

97
sys/ufs/chfs/debug.h Normal file
View File

@ -0,0 +1,97 @@
/* $NetBSD: debug.h,v 1.1 2011/11/24 15:51:32 ahoka Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
* University of Szeged, Hungary
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* 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.
*/
/*
* XipFFS -- Xip Flash File System
*
* Copyright (C) 2009 Ferenc Havasi <havasi@inf.u-szeged.hu>,
* Zoltan Sogor <weth@inf.u-szeged.hu>,
* ...
* University of Szeged, Hungary
*
*
* For licensing information, see the file 'LICENCE' in this directory.
*
*/
#ifndef __CHFS_DEBUG_H__
#define __CHFS_DEBUG_H__
#define CHFS_ERROR_PREFIX "[CHFS ERROR]"
#define CHFS_WARNING_PREFIX "[CHFS WARNING]"
#define CHFS_NOTICE_PREFIX "[CHFS NOTICE]"
#define CHFS_DBG_PREFIX "[CHFS DBG]"
#define CHFS_DBG2_PREFIX "[CHFS DBG2]"
#define CHFS_DBG_EBH_PREFIX "[CHFS DBG EBH]"
#define CHFS_DBG_GC_PREFIX "[CHFS_GC DBG]"
#define unlikely(x) __builtin_expect ((x), 0)
#define debug_msg(pref, fmt, ...) \
do { \
printf(pref \
" %s: " fmt, __FUNCTION__ , ##__VA_ARGS__); \
} while(0)
#define chfs_assert(expr) do { \
if (unlikely(!(expr))) { \
printf("CHFS assert failed in %s at %u\n", \
__func__, __LINE__); \
/*dump_stack();*/ \
} \
} while (0)
#ifdef DBG_MSG
#define chfs_err(fmt, ...) debug_msg(CHFS_ERROR_PREFIX, fmt, ##__VA_ARGS__)
#define chfs_warn(fmt, ...) debug_msg(CHFS_WARNING_PREFIX, fmt, ##__VA_ARGS__)
#define chfs_noti(fmt, ...) debug_msg(CHFS_NOTICE_PREFIX, fmt, ##__VA_ARGS__)
#define dbg(fmt, ...) debug_msg(CHFS_DBG_PREFIX, fmt, ##__VA_ARGS__)
#define dbg2(fmt, ...) debug_msg(CHFS_DBG2_PREFIX(fmt, ##__VA_ARGS__)
#define dbg_ebh(fmt, ...) debug_msg(CHFS_DBG_EBH_PREFIX, fmt, ##__VA_ARGS__)
#else
#define chfs_err(fmt, ...) debug_msg(CHFS_ERROR_PREFIX, fmt, ##__VA_ARGS__)
#define chfs_warn(fmt, ...) debug_msg(CHFS_WARNING_PREFIX, fmt, ##__VA_ARGS__)
#define chfs_noti(fmt, ...) debug_msg(CHFS_NOTICE_PREFIX, fmt, ##__VA_ARGS__)
#define dbg(fmt, ...)
#define dbg2(fmt, ...)
#define dbg_ebh(fmt, ...)
#endif
#ifdef DBG_MSG_GC
#define dbg_gc(fmt, ...) debug_msg(CHFS_DBG_GC_PREFIX, fmt, ##__VA_ARGS__)
#else
#define dbg_gc(fmt, ...)
#endif
#endif /* __CHFS_DEBUG_H__ */

2140
sys/ufs/chfs/ebh.c Normal file

File diff suppressed because it is too large Load Diff

318
sys/ufs/chfs/ebh.h Normal file
View File

@ -0,0 +1,318 @@
/* $NetBSD: ebh.h,v 1.1 2011/11/24 15:51:32 ahoka Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
* University of Szeged, Hungary
* Copyright (c) 2010 David Tengeri <dtengeri@inf.u-szeged.hu>
* Copyright (c) 2010 Adam Hoka <ahoka@NetBSD.org>
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* 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.
*/
/*
* ebh.h
*
* Created on: 2009.11.03.
* Author: dtengeri
*/
#ifndef EBH_H_
#define EBH_H_
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/cdefs.h>
#include <sys/stdint.h>
#include <sys/types.h>
#include <sys/tree.h>
#include <sys/queue.h>
#include <sys/kmem.h>
#include <sys/endian.h>
#include <sys/rwlock.h>
#include <sys/condvar.h>
#include <sys/mutex.h>
#include <sys/kthread.h>
#include <dev/flash/flash.h>
#include <ufs/chfs/ebh_media.h>
#include <ufs/chfs/debug.h>
#include <ufs/chfs/ebh_misc.h>
/* Maximum retries when getting new PEB before exit with failure */
#define CHFS_MAX_GET_PEB_RETRIES 2
/**
* LEB status
*
*/
enum {
EBH_LEB_UNMAPPED = -1,
EBH_LEB_MAPPED,
EBH_LEB_DIRTY,
EBH_LEB_INVALID,
EBH_LEB_ERASE,
EBH_LEB_ERASED,
EBH_LEB_FREE,
};
/**
* EB header status
*/
enum {
EBHDR_LEB_OK = 0,
EBHDR_LEB_DIRTY,
EBHDR_LEB_INVALIDATED,
EBHDR_LEB_BADMAGIC,
EBHDR_LEB_BADCRC,
EBHDR_LEB_FREE,
EBHDR_LEB_NO_HDR,
};
struct chfs_ebh;
/**
* struct chfs_ltree_entry - an netry in the lock tree
* @rb: RB-node of the tree
* @lnr: logical eraseblock number
* @users: counts the tasks that are using or want to use the eraseblock
* @mutex: read/write mutex to lock the eraseblock
*/
struct chfs_ltree_entry {
RB_ENTRY(chfs_ltree_entry) rb;
int lnr;
int users;
krwlock_t mutex;
};
/* Generate structure for Lock tree's red-black tree */
RB_HEAD(ltree_rbtree, chfs_ltree_entry);
/**
* struct chfs_scan_leb - scanning infomration about a physical eraseblock
* @erase_cnt: erase counter
* @pebnr: physical eraseblock number
* @info: the status of the PEB's eraseblock header when NOR serial when NAND
* @u.list: link in one of the eraseblock list
* @u.rb: link in the used RB-tree of chfs_scan_info
*/
struct chfs_scan_leb {
int erase_cnt;
int pebnr;
int lnr;
uint64_t info;
union {
TAILQ_ENTRY(chfs_scan_leb) queue;
RB_ENTRY(chfs_scan_leb) rb;
} u;
};
TAILQ_HEAD(scan_leb_queue, chfs_scan_leb);
RB_HEAD(scan_leb_used_rbtree, chfs_scan_leb);
/**
* struct chfs_scan_info - chfs scanning information
* @corrupted: queue of corrupted physical eraseblocks
* @free: queue of free physical eraseblocks
* @erase: queue of the physical eraseblocks signed to erase
* @erased: queue of physical eraseblocks that contain no header
* @used: RB-tree of used PEBs describing by chfs_scan_leb
* @sum_of_ec: summary of erase counters
* @num_of_eb: number of free and used eraseblocks
* @bad_peb_cnt: counter of bad eraseblocks
*
* This structure contains information about the scanning for further
* processing.
*/
struct chfs_scan_info {
struct scan_leb_queue corrupted;
struct scan_leb_queue free;
struct scan_leb_queue erase;
struct scan_leb_queue erased;
struct scan_leb_used_rbtree used;
uint64_t sum_of_ec;
int num_of_eb;
int bad_peb_cnt;
};
/**
* struct chfs_peb - PEB information for erasing and wear leveling
* @erase_cnt: erase counter of the physical eraseblock
* @pebnr: physical eraseblock number
* @u.queue: link to the queue of the PEBs waiting for erase
* @u.rb: link to the RB-tree to the free PEBs
*/
struct chfs_peb {
int erase_cnt;
int pebnr;
union {
TAILQ_ENTRY(chfs_peb) queue;
RB_ENTRY(chfs_peb) rb;
} u;
};
/* Generate queue and rb-tree structures. */
TAILQ_HEAD(peb_queue, chfs_peb);
RB_HEAD(peb_free_rbtree, chfs_peb);
RB_HEAD(peb_in_use_rbtree, chfs_peb);
/**
* struct chfs_eb_hdr - in-memory representation of eraseblock headers
* @ec_hdr: erase counter header ob eraseblock
* @u.nor_hdr: eraseblock header on NOR flash
* @u.nand_hdr: eraseblock header on NAND flash
*/
struct chfs_eb_hdr {
struct chfs_eb_ec_hdr ec_hdr;
union {
struct chfs_nor_eb_hdr nor_hdr;
struct chfs_nand_eb_hdr nand_hdr;
} u;
};
/*
* struct chfs_ebh_ops - collection of operations which
* depends on flash type
* *************************************************************************** *
* Direct flash operations:
*
* @read_eb_hdr: read eraseblock header from media
* @write_eb_hdr: write eraseblock header to media
* @check_eb_hdr: validates eraseblock header
* @mark_eb_hdr_dirty_flash: marks eraseblock dirty on flash
* @invalidate_eb_hdr: invalidates eraseblock header
* @mark_eb_hdr_free: marks eraseblock header free (after erase)
* *************************************************************************** *
* Scanning operations:
*
* @process_eb: process an eraseblock information at scan
* *************************************************************************** *
* Misc operations:
*
* @create_eb_hdr: creates an eraseblock header based on flash type
* @calc_data_offs: calculates where the data starts
*/
struct chfs_ebh_ops {
int (*read_eb_hdr)(struct chfs_ebh *ebh, int pebnr,
struct chfs_eb_hdr *ebhdr);
int (*write_eb_hdr)(struct chfs_ebh *ebh, int pebnr,
struct chfs_eb_hdr *ebhdr);
int (*check_eb_hdr)(struct chfs_ebh *ebh, void *buf);
int (*mark_eb_hdr_dirty_flash)(struct chfs_ebh *ebh, int pebnr, int lid);
int (*invalidate_eb_hdr)(struct chfs_ebh *ebh, int pebnr);
int (*mark_eb_hdr_free)(struct chfs_ebh *ebh, int pebnr, int ec);
int (*process_eb)(struct chfs_ebh *ebh, struct chfs_scan_info *si,
int pebnr, struct chfs_eb_hdr *ebhdr);
int (*create_eb_hdr)(struct chfs_eb_hdr *ebhdr, int lnr);
int (*calc_data_offs)(struct chfs_ebh *ebh, int pebnr, int offset);
};
/**
* struct erase_thread - background thread for erasing
* @thread: pointer to thread structure
* @wakeup: conditional variable for sleeping if there isn't any job to do
* @running: flag to signal a thread shutdown
*/
struct erase_thread {
lwp_t *eth_thread;
kcondvar_t eth_wakeup;
bool eth_running;
};
/**
* struct chfs_ebh - eraseblock handler descriptor
* @mtd: mtd device descriptor
* @eb_size: eraseblock size
* @peb_nr: number of PEBs
* @lmap: LEB to PEB mapping
* @layout_map: the LEBs layout (NOT USED YET)
* @ltree: the lock tree
* @ltree_lock: protects the tree
* @alc_mutex: serializes "atomic LEB change" operation
* @free: RB-tree of the free easeblocks
* @in_use: RB-tree of PEBs are in use
* @to_erase: list of the PEBs waiting for erase
* @fully_erased: list of PEBs that have been erased but don't have header
* @erase_lock: list and tree lock for fully_erased and to_erase lists and
* for the free RB-tree
* @bg_erase: background thread for eraseing PEBs.
* @ops: collection of operations which depends on flash type
* @max_serial: max serial number of eraseblocks, only used on NAND
*/
struct chfs_ebh {
struct peb_free_rbtree free;
struct peb_in_use_rbtree in_use;
struct peb_queue to_erase;
struct peb_queue fully_erased;
struct erase_thread bg_erase;
device_t flash_dev;
const struct flash_interface *flash_if;
struct chfs_ebh_ops *ops;
uint64_t *max_serial;
int *lmap;
//int *layout_map;
struct ltree_rbtree ltree;
//struct mutex alc_mutex;
kmutex_t ltree_lock;
kmutex_t alc_mutex;
kmutex_t erase_lock;
size_t eb_size;
size_t peb_nr;
flash_size_t flash_size;
};
/**
* struct chfs_erase_info_priv - private information for erase
* @ebh: eraseblock handler
* @peb: physical eraseblock information
*/
struct chfs_erase_info_priv {
struct chfs_ebh *ebh;
struct chfs_peb *peb;
};
/* ebh.c */
int ebh_open(struct chfs_ebh *ebh, dev_t dev);
int ebh_close(struct chfs_ebh *ebh);
int ebh_read_leb(struct chfs_ebh *ebh, int lnr, char *buf,
uint32_t offset, size_t len, size_t *retlen);
int ebh_write_leb(struct chfs_ebh *ebh, int lnr, char *buf,
uint32_t offset, size_t len, size_t *retlen);
int ebh_erase_leb(struct chfs_ebh *ebh, int lnr);
int ebh_map_leb(struct chfs_ebh *ebh, int lnr);
int ebh_unmap_leb(struct chfs_ebh *ebh, int lnr);
int ebh_is_mapped(struct chfs_ebh *ebh, int lnr);
int ebh_change_leb(struct chfs_ebh *ebh, int lnr, char *buf,
size_t len, size_t *retlen);
#endif /* EBH_H_ */

116
sys/ufs/chfs/ebh_media.h Normal file
View File

@ -0,0 +1,116 @@
/* $NetBSD: ebh_media.h,v 1.1 2011/11/24 15:51:32 ahoka Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
* University of Szeged, Hungary
* Copyright (C) 2009 Ferenc Havasi <havasi@inf.u-szeged.hu>
* Copyright (C) 2009 Zoltan Sogor <weth@inf.u-szeged.hu>
* Copyright (C) 2009 David Tengeri <dtengeri@inf.u-szeged.hu>
* Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* 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.
*/
#ifndef EBH_MEDIA_H_
#define EBH_MEDIA_H_
#ifndef _LE_TYPES
#define _LE_TYPES
typedef uint16_t le16;
typedef uint32_t le32;
typedef uint64_t le64;
#endif
/*****************************************************************************/
/* EBH specific structures */
/*****************************************************************************/
#define CHFS_MAGIC_BITMASK 0x53454452
#define CHFS_LID_NOT_DIRTY_BIT 0x80000000
#define CHFS_LID_DIRTY_BIT_MASK 0x7fffffff
/* sizeof(crc) + sizeof(lid) */
#define CHFS_INVALIDATE_SIZE 8
/* Size of magic + crc_ec + erase_cnt */
#define CHFS_EB_EC_HDR_SIZE sizeof(struct chfs_eb_ec_hdr)
/* Size of NOR eraseblock header */
#define CHFS_EB_HDR_NOR_SIZE sizeof(struct chfs_nor_eb_hdr)
/* Size of NAND eraseblock header */
#define CHFS_EB_HDR_NAND_SIZE sizeof(struct chfs_nand_eb_hdr)
/*
* chfs_eb_ec_hdr - erase counter header of eraseblock
* @magic: filesystem magic
* @crc_ec: CRC32 sum of erase counter
* @erase_cnt: erase counter
*
* This structure holds the erasablock description information.
* This will be written to the beginning of the eraseblock.
*
*/
struct chfs_eb_ec_hdr {
le32 magic;
le32 crc_ec;
le32 erase_cnt;
} __packed;
/**
* struct chfs_nor_eb_hdr - eraseblock header on NOR flash
* @crc: CRC32 sum
* @lid: logical identifier
*
* @lid contains the logical block reference but only the first 31 bit (0-30) is
* used. The 32th bit is for marking a lid dirty (marked for recovery purposes).
* If a new eraseblock is succesfully assigned with the same lid then the lid of
* the old one is zeroed. If power failure happened during this operation then
* the recovery detects that there is two eraseblock with the same lid, but one
* of them is marked (the old one).
*
* Invalidated eraseblock header means that the @crc and @lid is set to 0.
*/
struct chfs_nor_eb_hdr {
le32 crc;
le32 lid;
} __packed;
/**
* struct chfs_nand_eb_hdr - eraseblock header on NAND flash
* @crc: CRC32 sum
* @lid: logical identifier
* @serial: layout of the lid
*
* @serial is an unique number. Every eraseblock header on NAND flash has its
* own serial. If there are two eraseblock on the flash referencing to the same
* logical eraseblock, the one with bigger serial is the newer.
*/
struct chfs_nand_eb_hdr {
le32 crc;
le32 lid;
le64 serial;
} __packed;
#endif /* EBH_MEDIA_H_ */

88
sys/ufs/chfs/ebh_misc.h Normal file
View File

@ -0,0 +1,88 @@
/* $NetBSD: ebh_misc.h,v 1.1 2011/11/24 15:51:32 ahoka Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
* University of Szeged, Hungary
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* 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.
*/
#ifndef EBH_MISC_H_
#define EBH_MISC_H_
/******************************************************************************/
/* EBH specific functions */
/******************************************************************************/
#define CHFS_GET_MEMBER_POS(type, member) \
((unsigned long)(&((type *)0)->member))
#define CHFS_GET_LID(lid) (le32toh(lid) & CHFS_LID_DIRTY_BIT_MASK)
/**
* EBH_TREE_DESTROY - destroys an RB-tree and frees the memory of its elements.
* @name - the RB-tree structure's name
* @head - pointer to the RB-tree's head
* @type - type of the elements
*/
#define EBH_TREE_DESTROY(name, head, type) \
{ \
type *var, *nxt; \
for (var = RB_MIN(name, head); var != NULL; var = nxt) { \
nxt = RB_NEXT(name, head, var); \
RB_REMOVE(name, head, var); \
kmem_free(var, sizeof(type)); \
} \
}
/* XXX HACK! we need a clean solution for destroying mutexes in trees */
#define EBH_TREE_DESTROY_MUTEX(name, head, type) \
{ \
type *var, *nxt; \
for (var = RB_MIN(name, head); var != NULL; var = nxt) { \
nxt = RB_NEXT(name, head, var); \
RB_REMOVE(name, head, var); \
rw_destroy(&var->mutex); \
kmem_free(var, sizeof(type)); \
} \
}
/**
* EBH_QUEUE_DESTROY - destroys a TAILQ and frees the memory of its elements.
* @head: pointer to the head of the queue
* @type: type of the elements
* @entry: name of TAILQ_ENTRY
*/
#define EBH_QUEUE_DESTROY(head, type, entry) \
{ \
type *var; \
while ((var = TAILQ_FIRST(head))) { \
TAILQ_REMOVE(head, var, entry); \
kmem_free(var, sizeof(type)); \
} \
}
#endif /* EBH_MISC_H_ */

200
sys/ufs/chfs/media.h Normal file
View File

@ -0,0 +1,200 @@
/*-
* Copyright (c) 2010 Department of Software Engineering,
* University of Szeged, Hungary
* Copyright (C) 2009 Ferenc Havasi <havasi@inf.u-szeged.hu>
* Copyright (C) 2009 Zoltan Sogor <weth@inf.u-szeged.hu>
* Copyright (C) 2009 David Tengeri <dtengeri@inf.u-szeged.hu>
* Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* 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.
*/
#ifndef __CHFS_MEDIA_H__
#define __CHFS_MEDIA_H__
#ifndef _LE_TYPES
#define _LE_TYPES
typedef uint16_t le16;
typedef uint32_t le32;
typedef uint64_t le64;
#endif
/*****************************************************************************/
/* File system specific structures */
/*****************************************************************************/
enum {
CHFS_NODETYPE_VNODE = 1,
CHFS_NODETYPE_DATA,
CHFS_NODETYPE_DIRENT,
CHFS_NODETYPE_PADDING,
};
//#define CHFS_NODE_HDR_SIZE 12 /* magic + type + length + hdr_crc */
#define CHFS_NODE_HDR_SIZE sizeof(struct chfs_flash_node_hdr)
/* Max size we have to read to get all info.
* It is max size of chfs_flash_dirent_node with max name length.
*/
#define CHFS_MAX_NODE_SIZE 299
/* This will identify CHfs nodes */
#define CHFS_FS_MAGIC_BITMASK 0x4AF1
/**
* struct chfs_flash_node_hdr - node header, its members are same for
* all nodes, used at scan
* @magic: filesystem magic
* @type: node type
* @length: length of node
* @hdr_crc: crc of the first 3 members
*/
struct chfs_flash_node_hdr
{
le16 magic;
le16 type;
le32 length;
le32 hdr_crc;
} __packed;
/**
* struct chfs_flash_vnode - vnode informations stored on flash
* @magic: filesystem magic
* @type: node type (CHFS_NODETYPE_VNODE)
* @length: length of node
* @hdr_crc: crc of the first 3 members
* @vno: vnode identifier id
* @version: vnode's version number
* @uid: owner of the file
* @gid: group of file
* @mode: permissions for vnode
* @dn_size: size of written out data nodes
* @atime: last access times
* @mtime: last modification time
* @ctime: change time
* @dsize: size of the node's data
* @node_crc: crc of full node
*/
struct chfs_flash_vnode
{
le16 magic; /*0 */
le16 type; /*2 */
le32 length; /*4 */
le32 hdr_crc; /*8 */
le64 vno; /*12*/
le64 version; /*20*/
le32 uid; /*28*/
le32 gid; /*32*/
le32 mode; /*36*/
le32 dn_size; /*40*/
le32 atime; /*44*/
le32 mtime; /*48*/
le32 ctime; /*52*/
le32 dsize; /*56*/
le32 node_crc; /*60*/
} __packed;
/**
* struct chfs_flash_data_node - node informations of data stored on flash
* @magic: filesystem magic
* @type: node type (CHFS_NODETYPE_DATA)
* @length: length of node with data
* @hdr_crc: crc of the first 3 members
* @vno: vnode identifier id
* @version: vnode's version number
* @offset: offset in the file where write begins
* @data_length: length of data
* @data_crc: crc of data
* @node_crc: crc of full node
* @data: array of data
*/
struct chfs_flash_data_node
{
le16 magic;
le16 type;
le32 length;
le32 hdr_crc;
le64 vno;
le64 version;
le64 offset;
le32 data_length;
le32 data_crc;
le32 node_crc;
uint8_t data[0];
} __packed;
/**
* struct chfs_flash_dirent_node - vnode informations stored on flash
* @magic: filesystem magic
* @type: node type (CHFS_NODETYPE_DIRENT)
* @length: length of node
* @hdr_crc: crc of the first 3 members
* @vno: vnode identifier id
* @pvno: vnode identifier id of parent vnode
* @version: vnode's version number
* @mctime:
* @nsize: length of name
* @dtype: file type
* @unused: just for padding
* @name_crc: crc of name
* @node_crc: crc of full node
* @name: name of the directory entry
*/
struct chfs_flash_dirent_node
{
le16 magic;
le16 type;
le32 length;
le32 hdr_crc;
le64 vno;
le64 pvno;
le64 version;
le32 mctime;
uint8_t nsize;
uint8_t dtype;
uint8_t unused[2];
le32 name_crc;
le32 node_crc;
uint8_t name[0];
} __packed;
/**
* struct chfs_flash_padding_node - node informations of data stored on
* flash
* @magic: filesystem magic
* @type: node type (CHFS_NODETYPE_PADDING)
* @length: length of node
* @hdr_crc: crc of the first 3 members
*/
struct chfs_flash_padding_node
{
le16 magic;
le16 type;
le32 length;
le32 hdr_crc;
} __packed;
#endif /* __CHFS_MEDIA_H__ */

View File

@ -1,9 +1,10 @@
# $NetBSD: files.ufs,v 1.26 2011/03/24 17:05:45 bouyer Exp $
# $NetBSD: files.ufs,v 1.27 2011/11/24 15:51:31 ahoka Exp $
deffs FFS
deffs EXT2FS
deffs MFS
deffs LFS
deffs CHFS
defflag opt_ffs.h FFS_EI FFS_NO_SNAPSHOT APPLE_UFS
UFS_DIRHASH
@ -22,18 +23,37 @@ file ufs/ext2fs/ext2fs_subr.c ext2fs
file ufs/ext2fs/ext2fs_vfsops.c ext2fs
file ufs/ext2fs/ext2fs_vnops.c ext2fs
file ufs/ffs/ffs_alloc.c ffs | lfs | mfs | ext2fs
file ufs/ffs/ffs_balloc.c ffs | lfs | mfs | ext2fs
file ufs/chfs/ebh.c chfs
file ufs/chfs/chfs_ihash.c chfs
file ufs/chfs/chfs_scan.c chfs
file ufs/chfs/chfs_write.c chfs
file ufs/chfs/chfs_vnode_cache.c chfs
file ufs/chfs/chfs_erase.c chfs
file ufs/chfs/chfs_build.c chfs
file ufs/chfs/chfs_wbuf.c chfs
file ufs/chfs/chfs_vnops.c chfs
file ufs/chfs/chfs_gc.c chfs
file ufs/chfs/chfs_nodeops.c chfs
file ufs/chfs/chfs_malloc.c chfs
file ufs/chfs/chfs_pool.c chfs
file ufs/chfs/debug.c chfs
file ufs/chfs/chfs_vnode.c chfs
file ufs/chfs/chfs_subr.c chfs
file ufs/chfs/chfs_vfsops.c chfs
file ufs/chfs/chfs_readinode.c chfs
file ufs/ffs/ffs_alloc.c ffs | lfs | mfs | ext2fs | chfs
file ufs/ffs/ffs_balloc.c ffs | lfs | mfs | ext2fs | chfs
file ufs/ffs/ffs_bswap.c (ffs | mfs) & ffs_ei
file ufs/ffs/ffs_inode.c ffs | lfs | mfs | ext2fs
file ufs/ffs/ffs_snapshot.c ffs | lfs | mfs | ext2fs
file ufs/ffs/ffs_subr.c ffs | lfs | mfs | ext2fs
file ufs/ffs/ffs_tables.c ffs | lfs | mfs | ext2fs
file ufs/ffs/ffs_vfsops.c ffs | lfs | mfs | ext2fs
file ufs/ffs/ffs_vnops.c ffs | lfs | mfs | ext2fs
file ufs/ffs/ffs_inode.c ffs | lfs | mfs | ext2fs | chfs
file ufs/ffs/ffs_snapshot.c ffs | lfs | mfs | ext2fs | chfs
file ufs/ffs/ffs_subr.c ffs | lfs | mfs | ext2fs | chfs
file ufs/ffs/ffs_tables.c ffs | lfs | mfs | ext2fs | chfs
file ufs/ffs/ffs_vfsops.c ffs | lfs | mfs | ext2fs | chfs
file ufs/ffs/ffs_vnops.c ffs | lfs | mfs | ext2fs | chfs
file ufs/ffs/ffs_wapbl.c ffs & wapbl
file ufs/ffs/ffs_appleufs.c ffs & apple_ufs
file ufs/ffs/ffs_quota2.c quota2 & (ffs | lfs | mfs | ext2fs)
file ufs/ffs/ffs_quota2.c quota2 & (ffs | lfs | mfs | ext2fs | chfs)
file ufs/lfs/lfs_alloc.c lfs
file ufs/lfs/lfs_balloc.c lfs
@ -53,17 +73,17 @@ file ufs/mfs/mfs_vfsops.c mfs
file ufs/mfs/mfs_vnops.c mfs
file ufs/mfs/mfs_miniroot.c
file ufs/ufs/ufs_bmap.c ffs | lfs | mfs | ext2fs
file ufs/ufs/ufs_dirhash.c (ffs | lfs | mfs | ext2fs) & ufs_dirhash
file ufs/ufs/ufs_bmap.c ffs | lfs | mfs | ext2fs | chfs
file ufs/ufs/ufs_dirhash.c (ffs | lfs | mfs | ext2fs | chfs) & ufs_dirhash
file ufs/ufs/ufs_extattr.c (ffs | mfs) & ufs_extattr
file ufs/ufs/ufs_ihash.c ffs | lfs | mfs | ext2fs
file ufs/ufs/ufs_inode.c ffs | lfs | mfs | ext2fs
file ufs/ufs/ufs_lookup.c ffs | lfs | mfs | ext2fs
file ufs/ufs/ufs_quota.c (quota | quota2) & (ffs | lfs | mfs | ext2fs)
file ufs/ufs/ufs_quota1.c quota & (ffs | lfs | mfs | ext2fs)
file ufs/ufs/ufs_quota2.c quota2 & (ffs | lfs | mfs | ext2fs)
file ufs/ufs/ufs_lookup.c ffs | lfs | mfs | ext2fs | chfs
file ufs/ufs/ufs_quota.c (quota | quota2) & (ffs | lfs | mfs | ext2fs | chfs)
file ufs/ufs/ufs_quota1.c quota & (ffs | lfs | mfs | ext2fs | chfs)
file ufs/ufs/ufs_quota2.c quota2 & (ffs | lfs | mfs | ext2fs | chfs)
file ufs/ufs/quota1_subr.c
file ufs/ufs/quota2_subr.c quota2 & (ffs | lfs | mfs | ext2fs)
file ufs/ufs/ufs_vfsops.c ffs | lfs | mfs | ext2fs
file ufs/ufs/ufs_vnops.c ffs | lfs | mfs | ext2fs
file ufs/ufs/quota2_subr.c quota2 & (ffs | lfs | mfs | ext2fs | chfs)
file ufs/ufs/ufs_vfsops.c ffs | lfs | mfs | ext2fs | chfs
file ufs/ufs/ufs_vnops.c ffs | lfs | mfs | ext2fs | chfs
file ufs/ufs/ufs_wapbl.c ffs & wapbl

View File

@ -1,4 +1,4 @@
/* $NetBSD: ufsmount.h,v 1.36 2011/03/06 17:08:39 bouyer Exp $ */
/* $NetBSD: ufsmount.h,v 1.37 2011/11/24 15:51:32 ahoka Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@ -81,12 +81,14 @@ struct ufsmount {
union { /* pointer to superblock */
struct fs *fs; /* FFS */
struct lfs *lfs; /* LFS */
struct m_ext2fs *e2fs; /* EXT2FS */
struct m_ext2fs *e2fs; /* EXT2FS */
struct chfs_mount *chfs; /* CHFS */
} ufsmount_u;
#define um_fs ufsmount_u.fs
#define um_lfs ufsmount_u.lfs
#define um_e2fs ufsmount_u.e2fs
#define um_e2fsb ufsmount_u.e2fs->s_es
#define um_chfs ufsmount_u.chfs
/* Extended attribute information. */
struct ufs_extattr_per_mount um_extattr;