Synchronize on NetBSD-CVS (2013/12/1 12:00:00 UTC)

- Fix for possible unset uid/gid in toproto
 - Fix for default mtree style
 - Update libelf
 - Importing libexecinfo
 - Resynchronize GCC, mpc, gmp, mpfr
 - build.sh: Replace params with show-params.
     This has been done as the make target has been renamed in the same
     way, while a new target named params has been added. This new
     target generates a file containing all the parameters, instead of
     printing it on the console.
 - Update test48 with new etc/services (Fix by Ben Gras <ben@minix3.org)
     get getservbyport() out of the inner loop

Change-Id: Ie6ad5226fa2621ff9f0dee8782ea48f9443d2091
This commit is contained in:
2014-07-28 17:05:06 +02:00
parent ff10274392
commit 84d9c625bf
4655 changed files with 379308 additions and 151050 deletions
+200 -199
View File
@@ -1,4 +1,4 @@
/* $NetBSD: chfs.h,v 1.4 2011/11/28 12:50:07 ahoka Exp $ */
/* $NetBSD: chfs.h,v 1.8 2012/10/19 12:44:39 ttoth Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
@@ -38,9 +38,12 @@
#ifndef __CHFS_H__
#define __CHFS_H__
#ifdef _KERNEL
#if 0
#define DBG_MSG
#define DBG_MSG_GC
#define DBG_MSG /* debug messages */
#define DBG_MSG_GC /* garbage collector's debug messages */
#endif
#include <sys/param.h>
@@ -71,26 +74,34 @@
TAILQ_HEAD(chfs_dirent_list, chfs_dirent);
#include "chfs_pool.h"
#endif /* _KERNEL */
#include "ebh.h"
#include "media.h"
#include "chfs_inode.h"
/* padding - last two bits used for node masks */
#define CHFS_PAD(x) (((x)+3)&~3)
#ifdef _KERNEL
#ifndef MOUNT_CHFS
#define MOUNT_CHFS "chfs"
#endif
#define CHFS_ROOTINO ROOTINO /* ROOTINO == 2 */
#endif /* MOUNT_CHFS */
/* state of a vnode */
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() */
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() */
};
/* size of the vnode cache (hashtable) */
#define VNODECACHE_SIZE 128
#define MAX_READ_FREE(chmp) (((chmp)->chm_ebh)->eb_size / 8)
@@ -98,8 +109,7 @@ enum {
#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)
/* node errors */
enum {
CHFS_NODE_OK = 0,
CHFS_NODE_BADMAGIC,
@@ -107,6 +117,7 @@ enum {
CHFS_NODE_BADNAMECRC
};
/* eraseblock states */
enum {
CHFS_BLK_STATE_FREE = 100,
CHFS_BLK_STATE_CLEAN,
@@ -117,25 +128,23 @@ enum {
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 - a reference to a node which is on the media */
struct chfs_node_ref
{
struct chfs_node_ref *nref_next;
uint32_t nref_lnr;
uint32_t nref_offset;
struct chfs_node_ref *nref_next; /* next data node which belongs to the same vnode */
uint32_t nref_lnr; /* nref's LEB number */
uint32_t nref_offset; /* nref's offset */
};
/* Constants for allocating node refs */
/*
* constants for allocating node refs
* they're allocated in blocks
*/
#define REFS_BLOCK_LEN (255/sizeof(struct chfs_node_ref))
#define REF_EMPTY_NODE (UINT_MAX)
#define REF_LINK_TO_NEXT (UINT_MAX - 1)
/* node masks - last two bits of the nodes ("state" of an nref) */
enum {
CHFS_NORMAL_NODE_MASK,
CHFS_UNCHECKED_NODE_MASK,
@@ -152,83 +161,84 @@ enum {
#define CHFS_GET_OFS(ofs) (ofs & ~ 3)
/*
* Nrefs are allocated in blocks, get the (in-memory) next. Usually the next
* doesn't belongs to the same vnode.
*/
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);
/* step to the next nref in the same block */
nref++;
//dbg("nref++: %u : %u\n", nref->nref_lnr, nref->nref_offset);
/* REF_LINK_TO_NEXT means that the next node will be in the next block */
if (nref->nref_lnr == REF_LINK_TO_NEXT) {
//dbg("link to next\n");
nref = nref->nref_next;
if (!nref)
return nref;
}
/* REF_EMPTY_NODE means that this is the last node */
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 - 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_node_ref *nref; /* nref of the dirent */
TAILQ_ENTRY(chfs_dirent) fds; /* directory entries */
uint64_t version; /* version */
ino_t vno; /* vnode number */
uint32_t nhash; /* name hash */
enum chtype type; /* type of the dirent */
uint8_t nsize; /* length of its name */
uint8_t name[0]; /* name of the directory */
};
/* struct chfs_tmp_dnode - used temporarly while building a data node */
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_full_dnode *node; /* associated full dnode */
uint64_t version; /* version of the tmp node */
uint32_t data_crc; /* CRC of the data */
uint16_t overlapped; /* is overlapped */
struct chfs_tmp_dnode *next; /* next tmp node */
};
/* struct chfs_tmp_dnode_info - tmp nodes are stored in rb trees */
struct chfs_tmp_dnode_info {
struct rb_node rb_node;
struct chfs_tmp_dnode *tmpnode;
struct rb_node rb_node; /* rb tree entry */
struct chfs_tmp_dnode *tmpnode; /* associated tmp node */
};
/* struct chfs_readinode_info - collection of tmp_dnodes */
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 rb_tree tdi_root; /* root of the rb tree */
struct chfs_tmp_dnode_info *mdata_tn; /* metadata (eg: symlink) */
uint64_t highest_version; /* highest version of the nodes */
struct chfs_node_ref *latest_ref; /* latest node reference */
};
/* struct chfs_full_dnode - full data node */
struct chfs_full_dnode {
struct chfs_node_ref *nref;
uint64_t ofs;
uint32_t size;
uint32_t frags;
struct chfs_node_ref *nref; /* nref of the node */
uint64_t ofs; /* offset of the data node */
uint32_t size; /* size of the data node */
uint32_t frags; /* number of fragmentations */
};
/* struct chfs_node_frag - a fragment of a data node */
struct chfs_node_frag {
struct rb_node rb_node;
struct chfs_full_dnode *node;
uint32_t size;
uint64_t ofs;
struct rb_node rb_node; /* rb tree entry */
struct chfs_full_dnode *node; /* associated full dnode */
uint32_t size; /* size of the fragment */
uint64_t ofs; /* offset of the fragment */
};
/* find the first fragment of a data node */
static inline struct chfs_node_frag *
frag_first(struct rb_tree *tree)
{
@@ -239,6 +249,7 @@ frag_first(struct rb_tree *tree)
return frag;
}
/* find the last fragment of a data node */
static inline struct chfs_node_frag *
frag_last(struct rb_tree *tree)
{
@@ -249,149 +260,129 @@ frag_last(struct rb_tree *tree)
return frag;
}
/* iterate the fragtree */
#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 - in memory representation of a file or directory */
struct chfs_vnode_cache {
// struct chfs_dirent *scan_dirents;
/*
* void *p must be the first field of the structure
* but I can't remember where we use it and exactly for what
*/
void *p;
struct chfs_dirent_list scan_dirents;
struct chfs_dirent_list scan_dirents; /* used during scanning */
struct chfs_node_ref *v;
struct chfs_node_ref *dnode;
struct chfs_node_ref *dirents;
struct chfs_node_ref *v; /* list of node informations */
struct chfs_node_ref *dnode; /* list of data nodes */
struct chfs_node_ref *dirents; /* list of directory entries */
uint64_t *vno_version;
uint64_t highest_version;
uint64_t *vno_version; /* version of the vnode */
uint64_t highest_version; /* highest version of dnodes */
uint8_t flags;
uint16_t state;
ino_t vno;
ino_t pvno;
struct chfs_vnode_cache* next;
uint32_t nlink;
uint8_t flags; /* flags */
uint16_t state; /* actual state */
ino_t vno; /* vnode number */
ino_t pvno; /* vnode number of parent */
struct chfs_vnode_cache* next; /* next element of vnode cache */
uint32_t nlink; /* number of links to the file */
};
/* struct chfs_eraseblock - representation of an eraseblock */
struct chfs_eraseblock
{
uint32_t lnr;
uint32_t lnr; /* LEB number of the block*/
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;
TAILQ_ENTRY(chfs_eraseblock) queue; /* queue entry */
struct chfs_node_ref *first_node;
struct chfs_node_ref *last_node;
uint32_t unchecked_size; /* GC doesn't checked yet */
uint32_t used_size; /* size of nodes */
uint32_t dirty_size; /* size of obsoleted nodes */
uint32_t free_size; /* available size */
uint32_t wasted_size; /* paddings */
/* Next block to be garbage collected */
struct chfs_node_ref *gc_node;
struct chfs_node_ref *first_node; /* first node of the block */
struct chfs_node_ref *last_node; /* last node of the block */
struct chfs_node_ref *gc_node; /* next node from the block
which isn't garbage collected yet */
};
/* eraseblock queue */
TAILQ_HEAD(chfs_eraseblock_queue, chfs_eraseblock);
#define ALLOC_NORMAL 0
#define ALLOC_DELETION 1
#define ALLOC_GC 2
/* space allocation types */
#define ALLOC_NORMAL 0 /* allocating for normal usage (write, etc.) */
#define ALLOC_DELETION 1 /* allocating for deletion */
#define ALLOC_GC 2 /* allocating for the GC */
/* struct garbage_collector_thread - descriptor of GC thread */
struct garbage_collector_thread {
lwp_t *gcth_thread;
kcondvar_t gcth_wakeup;
bool gcth_running;
};
/* states of mounting */
#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 - CHFS main descriptor structure */
struct chfs_mount {
struct mount *chm_fsmp;
struct chfs_ebh *chm_ebh;
int chm_fs_version;
uint64_t chm_gbl_version;
ino_t chm_max_vno;
ino_t chm_checked_vno;
unsigned int chm_flags;
struct mount *chm_fsmp; /* general mount descriptor */
struct chfs_ebh *chm_ebh; /* eraseblock handler */
int chm_fs_version; /* version of the FS */
uint64_t chm_gbl_version; /* */
ino_t chm_max_vno; /* maximum of vnode numbers */
ino_t chm_checked_vno; /* vnode number of the last checked node */
unsigned int chm_flags; /* filesystem flags */
/* chm_lock_mountfields:
* Used to protect all the following fields. */
/*
* 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:
struct chfs_vnode_cache **chm_vnocache_hash; /* hash table
of vnode caches */
/*
* 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. */
* you must lock chm_lock_mountfields first.
*/
kmutex_t chm_lock_vnocache;
struct chfs_eraseblock *chm_blocks;
struct chfs_eraseblock *chm_blocks; /* list of eraseblocks */
struct chfs_node *chm_root;
struct chfs_node *chm_root; /* root node */
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:
uint32_t chm_free_size; /* available space */
uint32_t chm_dirty_size; /* size of contained obsoleted nodes */
uint32_t chm_unchecked_size; /* GC doesn't checked yet */
uint32_t chm_used_size; /* size of contained nodes */
uint32_t chm_wasted_size; /* padding */
/*
* 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. */
* you must lock chm_lock_mountfields first.
*/
kmutex_t chm_lock_sizes;
/*
* eraseblock queues
* free: completly free
* clean: contains only valid data
* dirty: contains valid and deleted data
* very_dirty: contains mostly deleted data (should be GC'd)
* erasable: doesn't contain valid data (should be erased)
* erase_pending: we can erase blocks from this queue
*/
struct chfs_eraseblock_queue chm_free_queue;
struct chfs_eraseblock_queue chm_clean_queue;
struct chfs_eraseblock_queue chm_dirty_queue;
@@ -399,22 +390,26 @@ struct chfs_mount {
struct chfs_eraseblock_queue chm_erasable_pending_wbuf_queue;
struct chfs_eraseblock_queue chm_erase_pending_queue;
/* reserved blocks */
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;
uint8_t chm_vdirty_blocks_gctrigger; /* GC trigger if the filesystem is
very dirty */
struct chfs_eraseblock *chm_nextblock;
struct chfs_eraseblock *chm_nextblock; /* next block for usage */
struct garbage_collector_thread chm_gc_thread;
struct chfs_eraseblock *chm_gcblock;
struct garbage_collector_thread chm_gc_thread; /* descriptor of
GC thread */
struct chfs_eraseblock *chm_gcblock; /* next block for GC */
int chm_nr_free_blocks;
int chm_nr_erasable_blocks;
int chm_nr_free_blocks; /* number of free blocks */
int chm_nr_erasable_blocks; /* number of eraseable blocks */
/* FS constants, used during writing */
int32_t chm_fs_bmask;
int32_t chm_fs_bsize;
int32_t chm_fs_qbmask;
@@ -425,21 +420,22 @@ struct chfs_mount {
/* 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:
size_t chm_wbuf_pagesize; /* writebuffer's size */
unsigned char* chm_wbuf; /* writebuffer */
size_t chm_wbuf_ofs; /* actual offset of writebuffer */
size_t chm_wbuf_len; /* actual length of writebuffer */
/*
* 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. */
* you must lock chm_lock_mountfields first.
*/
krwlock_t chm_lock_wbuf;
};
@@ -449,10 +445,11 @@ struct chfs_mount {
* specific ones.
*/
#define CHFS_OFFSET_DOT 0
#define CHFS_OFFSET_DOTDOT 1
#define CHFS_OFFSET_EOF 2
#define CHFS_OFFSET_FIRST 3
/* directory entry offsets */
#define CHFS_OFFSET_DOT 0 /* this */
#define CHFS_OFFSET_DOTDOT 1 /* parent */
#define CHFS_OFFSET_EOF 2 /* after last */
#define CHFS_OFFSET_FIRST 3 /* first */
/*---------------------------------------------------------------------------*/
@@ -488,6 +485,10 @@ 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_remove_node_from_list(struct chfs_mount *, struct chfs_vnode_cache *,
struct chfs_node_ref *, struct chfs_node_ref **);
void chfs_remove_and_obsolete(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 *,
@@ -502,28 +503,26 @@ 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 *);
/*
* Find out the corresponding vnode cache from an nref.
* Every last element of a linked list of nrefs is the vnode cache.
*/
static inline struct chfs_vnode_cache *
chfs_nref_to_vc(struct chfs_node_ref *nref)
{
/* iterate the whole list */
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: %ju, pvno: %ju, hv: %ju, nlink: %u\n", (intmax_t )vc->vno,
(intmax_t )vc->pvno, (intmax_t )vc->highest_version, vc->nlink);
//return ((struct chfs_vnode_cache *)nref);
return vc;
}
@@ -558,7 +557,9 @@ 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 *);
void chfs_remove_frags_of_node(struct chfs_mount *, struct rb_tree *,
struct chfs_node_ref *);
void chfs_kill_fragtree(struct chfs_mount *, 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 *,
@@ -631,7 +632,7 @@ 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 );
struct componentname *, enum vtype );
void chfs_set_vnode_size(struct vnode *, size_t);
void chfs_change_size_free(struct chfs_mount *,
struct chfs_eraseblock *, int);
@@ -647,8 +648,6 @@ void chfs_change_size_wasted(struct chfs_mount *,
/* 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 *);
@@ -665,7 +664,7 @@ int chfs_write_flash_dirent(struct chfs_mount *, struct chfs_inode *,
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);
struct chfs_inode *, const char *, int, enum chtype);
int chfs_do_unlink(struct chfs_inode *,
struct chfs_inode *, const char *, int);
@@ -673,18 +672,19 @@ int chfs_do_unlink(struct chfs_inode *,
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_filldir (struct uio *, ino_t, const char *, int, enum chtype);
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 */
/* chfs_map_leb - corresponds to ebh_map_leb */
static inline int
chfs_map_leb(struct chfs_mount *chmp, int lnr)
{
@@ -698,6 +698,7 @@ chfs_map_leb(struct chfs_mount *chmp, int lnr)
}
/* chfs_unmap_leb - corresponds to ebh_unmap_leb */
static inline int
chfs_unmap_leb(struct chfs_mount *chmp, int lnr)
{
@@ -710,6 +711,7 @@ chfs_unmap_leb(struct chfs_mount *chmp, int lnr)
return err;
}
/* chfs_read_leb - corresponds to ebh_read_leb */
static inline int
chfs_read_leb(struct chfs_mount *chmp, int lnr, char *buf,
int offset, int len, size_t *retlen)
@@ -724,6 +726,7 @@ chfs_read_leb(struct chfs_mount *chmp, int lnr, char *buf,
return err;
}
/* chfs_write_leb - corresponds to ebh_write_leb */
static inline int chfs_write_leb(struct chfs_mount *chmp, int lnr, char *buf,
int offset, int len, size_t *retlen)
{
@@ -736,9 +739,6 @@ static inline int chfs_write_leb(struct chfs_mount *chmp, int lnr, char *buf,
return err;
}
/******************************************************************************/
/* Code from dummyfs.h */
/******************************************************************************/
/* --------------------------------------------------------------------- */
#define CHFS_PAGES_RESERVED (4 * 1024 * 1024 / PAGE_SIZE)
@@ -765,4 +765,5 @@ CHFS_PAGES_MAX(struct chfs_mount *chmp)
#define IMPLIES(a, b) (!(a) || (b))
#define IFF(a, b) (IMPLIES(a, b) && IMPLIES(b, a))
#endif /* _KERNEL */
#endif /* __CHFS_H__ */
+3 -12
View File
@@ -1,4 +1,4 @@
/* $NetBSD: chfs_args.h,v 1.1 2011/11/24 15:51:31 ahoka Exp $ */
/* $NetBSD: chfs_args.h,v 1.2 2012/10/19 12:44:39 ttoth Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
@@ -35,19 +35,10 @@
#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 - arguments needed when mounting filesystem */
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;*/
int fl_index; /* index of the flash device in the flash layer */
};
#endif /* _FS_CHFS_CHFS_ARGS_H_ */
+34 -72
View File
@@ -1,4 +1,4 @@
/* $NetBSD: chfs_build.c,v 1.2 2011/11/24 21:22:39 agc Exp $ */
/* $NetBSD: chfs_build.c,v 1.5 2012/10/19 12:44:39 ttoth Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
@@ -31,9 +31,13 @@
*/
#include "chfs.h"
//#include </root/xipffs/netbsd.chfs/chfs.h>
/*
* chfs_calc_trigger_levels - setup filesystem parameters
* Setups filesystem parameters (reserved blocks and GC trigger level)
* for a specific flash.
*/
void
chfs_calc_trigger_levels(struct chfs_mount *chmp)
{
@@ -41,7 +45,7 @@ chfs_calc_trigger_levels(struct chfs_mount *chmp)
chmp->chm_resv_blocks_deletion = 2;
size = chmp->chm_ebh->flash_size / 50; //2% of flash size
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;
@@ -56,22 +60,18 @@ chfs_calc_trigger_levels(struct chfs_mount *chmp)
}
/**
/*
* 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
* 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");
struct chfs_dirent *fd, *tmpfd;
// for (fd = vc->scan_dirents; fd; fd = fd->next) {
TAILQ_FOREACH(fd, &vc->scan_dirents, fds) {
TAILQ_FOREACH_SAFE(fd, &vc->scan_dirents, fds, tmpfd) {
struct chfs_vnode_cache *child_vc;
if (!fd->vno)
@@ -82,9 +82,10 @@ chfs_build_set_vnodecache_nlink(struct chfs_mount *chmp,
mutex_exit(&chmp->chm_lock_vnocache);
if (!child_vc) {
chfs_mark_node_obsolete(chmp, fd->nref);
TAILQ_REMOVE(&vc->scan_dirents, fd, fds);
continue;
}
if (fd->type == VDIR) {
if (fd->type == CHT_DIR) {
if (child_vc->nlink < 1)
child_vc->nlink = 1;
@@ -94,26 +95,20 @@ chfs_build_set_vnodecache_nlink(struct chfs_mount *chmp,
fd->name, (unsigned long long)fd->vno,
(unsigned long long)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;
@@ -122,28 +117,28 @@ chfs_build_remove_unlinked_vnode(struct chfs_mount *chmp,
dbg("START\n");
dbg("vno: %llu\n", (unsigned long long)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
nref = vc->dnode;
/* 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;
}
vc->dnode = (struct chfs_node_ref *)vc;
nref = vc->dirents;
// The vnode cache is at the end of the dirent node's chain
/* 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;
}
vc->dirents = (struct chfs_node_ref *)vc;
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", (unsigned long long)fd->vno);
dbg(" ->version: %llu\n", (unsigned long long)fd->version);
@@ -151,7 +146,6 @@ chfs_build_remove_unlinked_vnode(struct chfs_mount *chmp,
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) {
@@ -165,16 +159,13 @@ chfs_build_remove_unlinked_vnode(struct chfs_mount *chmp,
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.
@@ -189,24 +180,23 @@ chfs_build_remove_unlinked_vnode(struct chfs_mount *chmp,
nref = vc->v;
while ((struct chfs_vnode_cache *)nref != vc) {
if (!CHFS_REF_OBSOLETE(nref))
chfs_mark_node_obsolete(chmp, nref);
chfs_mark_node_obsolete(chmp, nref);
nref = nref->nref_next;
}
vc->v = (struct chfs_node_ref *)vc;
mutex_enter(&chmp->chm_lock_vnocache);
if (vc->vno != CHFS_ROOTINO)
chfs_vnode_cache_set_state(chmp, vc, VNO_STATE_UNCHECKED);
vc->state = 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.
* 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:
@@ -220,7 +210,6 @@ 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;
@@ -229,17 +218,13 @@ chfs_build_filesystem(struct chfs_mount *chmp)
mutex_enter(&chmp->chm_lock_mountfields);
/**
* Step 1
*/
/* 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 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++;
@@ -258,7 +243,6 @@ chfs_build_filesystem(struct chfs_mount *chmp)
&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 >
@@ -304,9 +288,7 @@ chfs_build_filesystem(struct chfs_mount *chmp)
* Need check at erase + write + read...
*/
/**
* Step 2
*/
/* Step 2 */
chmp->chm_flags |= CHFS_MP_FLAG_BUILDING;
for (i = 0; i < VNODECACHE_SIZE; i++) {
vc = chmp->chm_vnocache_hash[i];
@@ -318,10 +300,7 @@ chfs_build_filesystem(struct chfs_mount *chmp)
}
}
/**
* Step 3
* Scan for vnodes with 0 nlink.
*/
/* Step 3 */
for (i = 0; i < VNODECACHE_SIZE; i++) {
vc = chmp->chm_vnocache_hash[i];
while (vc) {
@@ -330,18 +309,13 @@ chfs_build_filesystem(struct chfs_mount *chmp)
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);
@@ -360,37 +334,25 @@ chfs_build_filesystem(struct chfs_mount *chmp)
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
} else if (fd->type == CHT_DIR) {
/* 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);
notregvc = chfs_vnode_cache_get(chmp, fd->vno);
notregvc->state = 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
/* 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 -
+6 -19
View File
@@ -1,4 +1,4 @@
/* $NetBSD: chfs_erase.c,v 1.1 2011/11/24 15:51:31 ahoka Exp $ */
/* $NetBSD: chfs_erase.c,v 1.2 2012/10/19 12:44:39 ttoth Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
@@ -31,28 +31,17 @@
* 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
* 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
@@ -63,8 +52,6 @@ chfs_remap_leb(struct chfs_mount *chmp)
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));
@@ -102,7 +89,7 @@ chfs_remap_leb(struct chfs_mount *chmp)
free = cheb->free_size;
wasted = cheb->wasted_size;
// Free allocated node references for this eraseblock
/* Free allocated node references for this eraseblock */
chfs_free_node_refs(cheb);
err = chfs_unmap_leb(chmp, cheb->lnr);
@@ -112,7 +99,7 @@ chfs_remap_leb(struct chfs_mount *chmp)
err = chfs_map_leb(chmp, cheb->lnr);
if (err)
return err;
// Reset state to default and change chmp sizes too
/* 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);
@@ -127,7 +114,7 @@ chfs_remap_leb(struct chfs_mount *chmp)
cheb->first_node = NULL;
cheb->last_node = NULL;
//put it to free_queue
/* 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);
+180 -256
View File
File diff suppressed because it is too large Load Diff
+1 -9
View File
@@ -1,4 +1,4 @@
/* $NetBSD: chfs_ihash.c,v 1.1 2011/11/24 15:51:31 ahoka Exp $ */
/* $NetBSD: chfs_ihash.c,v 1.2 2012/10/19 12:44:39 ttoth Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
@@ -148,12 +148,9 @@ loop:
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;
}
@@ -164,22 +161,17 @@ loop:
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);
}
+59 -24
View File
@@ -1,4 +1,4 @@
/* $NetBSD: chfs_inode.h,v 1.1 2011/11/24 15:51:31 ahoka Exp $ */
/* $NetBSD: chfs_inode.h,v 1.7 2013/01/22 09:39:15 dholland Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
@@ -35,18 +35,51 @@
#ifndef __CHFS_INODE_H__
#define __CHFS_INODE_H__
#ifdef _KERNEL
#include <sys/vnode.h>
#include <sys/stat.h>
#include <ufs/ufs/ufsmount.h>
#include <miscfs/genfs/genfs_node.h>
#endif /* _KERNEL */
#define CHFS_ROOTINO 2
/* chfs file types */
enum chtype {
CHT_BLANK, /* empty type */
CHT_REG, /* regular file */
CHT_DIR, /* directory */
CHT_BLK, /* block device */
CHT_CHR, /* character device */
CHT_LNK, /* link */
CHT_SOCK, /* socket */
CHT_FIFO, /* fifo */
CHT_BAD /* bad type */
};
/* these macros are needed because the compatibility */
#define CHTTOVT(ch_type) (enum vtype)(ch_type)
#define VTTOCHT(v_type) (enum chtype)(v_type)
/* vtype replaced with chtype, these are only for backward compatibility */
static const enum chtype iftocht_tab[16] = {
CHT_BLANK, CHT_FIFO, CHT_CHR, CHT_BLANK,
CHT_DIR, CHT_BLANK, CHT_BLK, CHT_BLANK,
CHT_REG, CHT_BLANK, CHT_LNK, CHT_BLANK,
CHT_SOCK, CHT_BLANK, CHT_BLANK, CHT_BAD,
};
#define IFTOCHT(mode) (iftocht_tab[((mode) & S_IFMT) >> 12])
#ifdef _KERNEL
struct chfs_inode
{
kmutex_t inode_lock; /* lock the fields of chfs_inode */
struct genfs_node gnode;
kmutex_t inode_lock; /* lock the fields of chfs_inode */
LIST_ENTRY(chfs_inode) hash_entry; /* Hash chain. */
LIST_ENTRY(chfs_inode) hash_entry; /* hash chain */
struct ufsmount *ump; /* ufs mount - TODO we should remove it */
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 */
@@ -57,30 +90,28 @@ struct chfs_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 *fd; /* full dirent of this node */
struct chfs_dirent_list dents;
struct rb_tree fragtree; /* fragtree of inode */
struct rb_tree fragtree; /* fragtree of inode */
uint64_t version; /* version number */
//uint64_t highest_version; /* highest vers. num. (used at data nodes) */
uint64_t version; /* version number */
uint32_t mode; /* mode */
//int16_t nlink; /* link count */
uint64_t size; /* file byte count */
uint32_t mode; /* mode */
enum chtype ch_type; /* chfs file type */
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 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) */
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 */
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. */
@@ -106,13 +137,16 @@ struct chfs_inode
# undef ITOV
#endif
/* struct vnode to struct chfs_inode */
#define VTOI(vp) ((struct chfs_inode *)(vp)->v_data)
/* struct chfs_inode to struct vnode */
#define ITOV(ip) ((ip)->vp)
/* copied from ufs_dinode.h */
#define NDADDR 12 /* Direct addresses in inode. */
/* XXX copied from ufs_dinode.h and should not be duplicated here */
#define UFS_NDADDR 12 /* Direct addresses in inode. */
#define ROOTINO ((ino_t)2)
/* XXX this should not be duplicated here */
#define UFS_ROOTINO ((ino_t)2)
/* File permissions. */
#define IEXEC 0000100 /* Executable. */
@@ -133,4 +167,5 @@ struct chfs_inode
#define IFSOCK 0140000 /* UNIX domain socket. */
#define IFWHT 0160000 /* Whiteout. */
#endif /* _KERNEL */
#endif /* __CHFS_INODE_H__ */
+39 -26
View File
@@ -1,4 +1,4 @@
/* $NetBSD: chfs_malloc.c,v 1.1 2011/11/24 15:51:31 ahoka Exp $ */
/* $NetBSD: chfs_malloc.c,v 1.4 2012/10/19 12:44:39 ttoth Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
@@ -44,8 +44,9 @@ pool_cache_t chfs_node_frag_cache;
pool_cache_t chfs_tmp_dnode_cache;
pool_cache_t chfs_tmp_dnode_info_cache;
/* chfs_alloc_pool_caches - allocating pool caches */
int
chfs_alloc_pool_caches()
chfs_alloc_pool_caches(void)
{
chfs_vnode_cache = pool_cache_init(
sizeof(struct chfs_vnode_cache),
@@ -117,8 +118,9 @@ err_vnode:
return ENOMEM;
}
/* chfs_destroy_pool_caches - destroying pool caches */
void
chfs_destroy_pool_caches()
chfs_destroy_pool_caches(void)
{
if (chfs_vnode_cache)
pool_cache_destroy(chfs_vnode_cache);
@@ -145,6 +147,7 @@ chfs_destroy_pool_caches()
pool_cache_destroy(chfs_tmp_dnode_info_cache);
}
/* chfs_vnode_cache_alloc - allocating and initializing a vnode cache */
struct chfs_vnode_cache *
chfs_vnode_cache_alloc(ino_t vno)
{
@@ -153,6 +156,7 @@ chfs_vnode_cache_alloc(ino_t vno)
memset(vc, 0, sizeof(*vc));
vc->vno = vno;
/* vnode cache is the last element of all chain */
vc->v = (void *)vc;
vc->dirents = (void *)vc;
vc->dnode = (void *)vc;
@@ -162,14 +166,14 @@ chfs_vnode_cache_alloc(ino_t vno)
return vc;
}
/* chfs_vnode_cache_free - freeing a vnode cache */
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.
@@ -198,18 +202,15 @@ chfs_alloc_refblock(void)
return nref;
}
/**
* chfs_free_refblock - freeing a refblock
*/
/* 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.
@@ -222,7 +223,7 @@ chfs_alloc_node_ref(struct chfs_eraseblock *cheb)
nref = cheb->last_node;
if (!nref) {
//There haven't been any nref allocated for this block yet
/* There haven't been any nref allocated for this block yet */
nref = chfs_alloc_refblock();
cheb->first_node = nref;
@@ -235,6 +236,7 @@ chfs_alloc_node_ref(struct chfs_eraseblock *cheb)
nref++;
if (nref->nref_lnr == REF_LINK_TO_NEXT) {
/* this was the last element, allocate a new block */
new = chfs_alloc_refblock();
nref->nref_next = new;
nref = new;
@@ -249,10 +251,7 @@ chfs_alloc_node_ref(struct chfs_eraseblock *cheb)
return nref;
}
/**
* chfs_free_node_refs - freeing an eraseblock's node refs
* @cheb: eraseblock information structure
*/
/* chfs_free_node_refs - freeing an eraseblock's node refs */
void
chfs_free_node_refs(struct chfs_eraseblock *cheb)
{
@@ -271,6 +270,7 @@ chfs_free_node_refs(struct chfs_eraseblock *cheb)
}
}
/* chfs_alloc_dirent - allocating a directory entry */
struct chfs_dirent*
chfs_alloc_dirent(int namesize)
{
@@ -278,94 +278,104 @@ chfs_alloc_dirent(int namesize)
size_t size = sizeof(struct chfs_dirent) + namesize;
ret = kmem_alloc(size, KM_SLEEP);
//ret->alloc_size = size;
return ret;
}
/* chfs_free_dirent - freeing a directory entry */
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);
}
/* chfs_alloc_full_dnode - allocating a full data node */
struct chfs_full_dnode*
chfs_alloc_full_dnode()
chfs_alloc_full_dnode(void)
{
struct chfs_full_dnode *ret;
ret = kmem_alloc(sizeof(struct chfs_full_dnode), KM_SLEEP);
ret->nref = NULL;
ret->frags = 0;
return ret;
}
/* chfs_free_full_dnode - freeing a full data node */
void
chfs_free_full_dnode(struct chfs_full_dnode *fd)
{
kmem_free(fd,(sizeof(struct chfs_full_dnode)));
}
/* chfs_alloc_flash_vnode - allocating vnode info (used on flash) */
struct chfs_flash_vnode*
chfs_alloc_flash_vnode()
chfs_alloc_flash_vnode(void)
{
struct chfs_flash_vnode *ret;
ret = pool_cache_get(chfs_flash_vnode_cache, 0);
return ret;
}
/* chfs_free_flash_vnode - freeing vnode info */
void
chfs_free_flash_vnode(struct chfs_flash_vnode *fvnode)
{
pool_cache_put(chfs_flash_vnode_cache, fvnode);
}
/* chfs_alloc_flash_dirent - allocating a directory entry (used on flash) */
struct chfs_flash_dirent_node*
chfs_alloc_flash_dirent()
chfs_alloc_flash_dirent(void)
{
struct chfs_flash_dirent_node *ret;
ret = pool_cache_get(chfs_flash_dirent_cache, 0);
return ret;
}
/* chfs_free_flash_dirent - freeing a (flash) directory entry */
void
chfs_free_flash_dirent(struct chfs_flash_dirent_node *fdnode)
{
pool_cache_put(chfs_flash_dirent_cache, fdnode);
}
/* chfs_alloc_flash_dnode - allocating a data node (used on flash) */
struct chfs_flash_data_node*
chfs_alloc_flash_dnode()
chfs_alloc_flash_dnode(void)
{
struct chfs_flash_data_node *ret;
ret = pool_cache_get(chfs_flash_dnode_cache, 0);
return ret;
}
/* chfs_free_flash_dnode - freeing a (flash) data node */
void
chfs_free_flash_dnode(struct chfs_flash_data_node *fdnode)
{
pool_cache_put(chfs_flash_dnode_cache, fdnode);
}
/* chfs_alloc_node_frag - allocating a fragment of a node */
struct chfs_node_frag*
chfs_alloc_node_frag()
chfs_alloc_node_frag(void)
{
struct chfs_node_frag *ret;
ret = pool_cache_get(chfs_node_frag_cache, 0);
return ret;
}
/* chfs_free_node_frag - freeing a fragment of a node */
void
chfs_free_node_frag(struct chfs_node_frag *frag)
{
pool_cache_put(chfs_node_frag_cache, frag);
}
/* chfs_alloc_tmp_dnode - allocating a temporarly used dnode */
struct chfs_tmp_dnode *
chfs_alloc_tmp_dnode()
chfs_alloc_tmp_dnode(void)
{
struct chfs_tmp_dnode *ret;
ret = pool_cache_get(chfs_tmp_dnode_cache, 0);
@@ -373,14 +383,16 @@ chfs_alloc_tmp_dnode()
return ret;
}
/* chfs_free_tmp_dnode - freeing a temporarly used dnode */
void
chfs_free_tmp_dnode(struct chfs_tmp_dnode *td)
{
pool_cache_put(chfs_tmp_dnode_cache, td);
}
/* chfs_alloc_tmp_dnode_info - allocating a temporarly used dnode descriptor */
struct chfs_tmp_dnode_info *
chfs_alloc_tmp_dnode_info()
chfs_alloc_tmp_dnode_info(void)
{
struct chfs_tmp_dnode_info *ret;
ret = pool_cache_get(chfs_tmp_dnode_info_cache, 0);
@@ -388,6 +400,7 @@ chfs_alloc_tmp_dnode_info()
return ret;
}
/* chfs_free_tmp_dnode_info - freeing a temporarly used dnode descriptor */
void
chfs_free_tmp_dnode_info(struct chfs_tmp_dnode_info *di)
{
+99 -75
View File
@@ -1,4 +1,4 @@
/* $NetBSD: chfs_nodeops.c,v 1.1 2011/11/24 15:51:31 ahoka Exp $ */
/* $NetBSD: chfs_nodeops.c,v 1.3 2012/10/19 12:44:39 ttoth Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
@@ -35,13 +35,10 @@
#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.
* Returns zero in case of success, 1 in case of fail.
*/
int
chfs_update_eb_dirty(struct chfs_mount *chmp,
@@ -59,19 +56,14 @@ chfs_update_eb_dirty(struct chfs_mount *chmp,
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.
*/
@@ -80,6 +72,8 @@ chfs_add_node_to_list(struct chfs_mount *chmp,
struct chfs_vnode_cache *vc,
struct chfs_node_ref *new, struct chfs_node_ref **list)
{
KASSERT(mutex_owned(&chmp->chm_lock_vnocache));
struct chfs_node_ref *nextref = *list;
struct chfs_node_ref *prevref = NULL;
@@ -104,10 +98,13 @@ chfs_add_node_to_list(struct chfs_mount *chmp,
CHFS_GET_OFS(nextref->nref_offset) ==
CHFS_GET_OFS(new->nref_offset)) {
new->nref_next = nextref->nref_next;
chfs_mark_node_obsolete(chmp, nextref);
} else {
new->nref_next = nextref;
}
KASSERT(new->nref_next != NULL);
if (prevref) {
prevref->nref_next = new;
} else {
@@ -115,18 +112,74 @@ chfs_add_node_to_list(struct chfs_mount *chmp,
}
}
/*
* chfs_remove_node_from_list - removes a node from a list
* Usually used for removing data nodes.
*/
void
chfs_remove_node_from_list(struct chfs_mount *chmp,
struct chfs_vnode_cache *vc,
struct chfs_node_ref *old_nref, struct chfs_node_ref **list)
{
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
KASSERT(mutex_owned(&chmp->chm_lock_vnocache));
struct chfs_node_ref *tmpnref;
if (*list == (struct chfs_node_ref *)vc) {
/* list is empty */
return;
}
KASSERT(old_nref->nref_next != NULL);
if (*list == old_nref) {
*list = old_nref->nref_next;
} else {
tmpnref = *list;
while (tmpnref->nref_next &&
tmpnref->nref_next != (struct chfs_node_ref *)vc) {
if (tmpnref->nref_next == old_nref) {
tmpnref->nref_next = old_nref->nref_next;
break;
}
tmpnref = tmpnref->nref_next;
}
}
}
/*
* chfs_remove_and_obsolete - removes a node from a list and obsoletes the nref
* We should use this function carefully on data nodes,
* because removing a frag will also obsolete the node ref.
*/
void
chfs_remove_and_obsolete(struct chfs_mount *chmp,
struct chfs_vnode_cache *vc,
struct chfs_node_ref *old_nref, struct chfs_node_ref **list)
{
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
KASSERT(mutex_owned(&chmp->chm_lock_vnocache));
chfs_remove_node_from_list(chmp, vc, old_nref, list);
dbg("[MARK] vno: %llu lnr: %u ofs: %u\n", vc->vno, old_nref->nref_lnr,
old_nref->nref_offset);
chfs_mark_node_obsolete(chmp, old_nref);
}
/* chfs_add_fd_to_inode - adds a directory entry to an inode */
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;
/* update highest version */
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 */
@@ -135,17 +188,18 @@ chfs_add_fd_to_inode(struct chfs_mount *chmp,
} 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);
mutex_enter(&chmp->chm_lock_vnocache);
chfs_remove_and_obsolete(chmp, parent->chvc, fd->nref,
&parent->chvc->dirents);
mutex_exit(&chmp->chm_lock_vnocache);
}
chfs_free_dirent(fd);
// *prev = new;//XXX
} else {
/* new is older (normally it's not an option) */
chfs_mark_node_obsolete(chmp, new->nref);
chfs_free_dirent(new);
}
@@ -155,66 +209,48 @@ chfs_add_fd_to_inode(struct chfs_mount *chmp,
/* 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
}
/* chfs_add_vnode_ref_to_vc - adds a vnode info to the vnode cache */
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;
KASSERT(mutex_owned(&chmp->chm_lock_vnocache));
struct chfs_node_ref *nref;
/* store only the last one, drop the others */
while (vc->v != (struct chfs_node_ref *)vc) {
nref = vc->v;
chfs_remove_and_obsolete(chmp, vc, nref, &vc->v);
}
new->nref_next = (struct chfs_node_ref *)vc;
vc->v = new;
}
/* chfs_nref_next - step to the next in-memory nref */
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
/* end of chain */
if (!nref->nref_next)
return NULL;
/* link to the next block */
nref = nref->nref_next;
}
//end of chain
/* end of chain */
if (nref->nref_lnr == REF_EMPTY_NODE)
return NULL;
return nref;
}
/* chfs_nref_len - calculates the length of an nref */
int
chfs_nref_len(struct chfs_mount *chmp,
struct chfs_eraseblock *cheb, struct chfs_node_ref *nref)
@@ -229,18 +265,14 @@ chfs_nref_len(struct chfs_mount *chmp,
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
*/
/* chfs_mark_node_obsolete - marks a node as obsolete */
void
chfs_mark_node_obsolete(struct chfs_mount *chmp,
struct chfs_node_ref *nref)
@@ -268,19 +300,14 @@ chfs_mark_node_obsolete(struct chfs_mount *chmp,
#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);
@@ -312,8 +339,8 @@ chfs_mark_node_obsolete(struct chfs_mount *chmp,
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
/* 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;
@@ -384,10 +411,8 @@ chfs_mark_node_obsolete(struct chfs_mount *chmp,
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.
@@ -424,6 +449,11 @@ chfs_close_eraseblock(struct chfs_mount *chmp,
return 0;
}
/*
* chfs_reserve_space_normal -
* checks available space and calls chfs_reserve_space
* used during writing
*/
int
chfs_reserve_space_normal(struct chfs_mount *chmp, uint32_t size, int prio)
{
@@ -456,8 +486,6 @@ chfs_reserve_space_normal(struct chfs_mount *chmp, uint32_t size, int prio)
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 ||
@@ -479,6 +507,7 @@ out:
}
/* chfs_reserve_space_gc - tries to reserve space for GC */
int
chfs_reserve_space_gc(struct chfs_mount *chmp, uint32_t size)
{
@@ -500,11 +529,8 @@ chfs_reserve_space_gc(struct chfs_mount *chmp, uint32_t 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
@@ -521,8 +547,6 @@ chfs_reserve_space(struct chfs_mount *chmp, uint32_t size)
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);
/*
+3 -6
View File
@@ -1,4 +1,4 @@
/* $NetBSD: chfs_pool.c,v 1.1 2011/11/24 15:51:31 ahoka Exp $ */
/* $NetBSD: chfs_pool.c,v 1.2 2012/02/28 02:48:39 christos Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
@@ -50,9 +50,6 @@
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 = {
@@ -104,7 +101,7 @@ chfs_pool_page_alloc(struct pool *pp, int flags)
atomic_dec_uint(&chmp->chm_pages_used);
return NULL;
}
page = pool_page_alloc_nointr(pp, flags | PR_WAITOK);
page = pool_get(pp, flags | PR_WAITOK);
if (page == NULL) {
atomic_dec_uint(&chmp->chm_pages_used);
}
@@ -125,7 +122,7 @@ chfs_pool_page_free(struct pool *pp, void *v)
chmp = chpp->chp_mount;
atomic_dec_uint(&chmp->chm_pages_used);
pool_page_free_nointr(pp, v);
pool_put(pp,v);
}
/* --------------------------------------------------------------------- */
+190 -132
View File
@@ -1,4 +1,4 @@
/* $NetBSD: chfs_readinode.c,v 1.2 2011/11/24 21:09:37 agc Exp $ */
/* $NetBSD: chfs_readinode.c,v 1.8 2013/10/20 17:18:38 christos Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
@@ -33,13 +33,6 @@
* SUCH DAMAGE.
*/
/*
* chfs_readinode.c
*
* Created on: 2010.05.31.
* Author: dtengeri
*/
#include <sys/buf.h>
#include "chfs.h"
@@ -82,11 +75,7 @@ int chfs_build_fragtree(struct chfs_mount *,
/*
* --------------------------
* tmp node rbtree operations
* --------------------------
*/
/* tmp node rbtree operations */
static signed int
tmp_node_compare_nodes(void *ctx, const void *n1, const void *n2)
{
@@ -113,11 +102,7 @@ const rb_tree_ops_t tmp_node_rbtree_ops = {
};
/*
* ---------------------------
* frag node rbtree operations
* ---------------------------
*/
/* frag node rbtree operations */
static signed int
frag_compare_nodes(void *ctx, const void *n1, const void *n2)
{
@@ -145,12 +130,7 @@ const rb_tree_ops_t frag_rbtree_ops = {
/*
* -------------------
* tmp node operations
* -------------------
*/
/*
* Check the data CRC of the node.
* chfs_check_td_data - checks the data CRC of the node
*
* Returns: 0 - if everything OK;
* 1 - if CRC is incorrect;
@@ -176,6 +156,7 @@ chfs_check_td_data(struct chfs_mount *chmp,
if (!len)
return 0;
/* Read data. */
buf = kmem_alloc(len, KM_SLEEP);
if (!buf) {
dbg("allocating error\n");
@@ -183,11 +164,12 @@ chfs_check_td_data(struct chfs_mount *chmp,
}
err = chfs_read_leb(chmp, nref->nref_lnr, buf, ofs, len, &retlen);
if (err) {
dbg("error wile reading: %d\n", err);
dbg("error while reading: %d\n", err);
err = 2;
goto out;
}
/* Check crc. */
if (len != retlen) {
dbg("len:%zu, retlen:%zu\n", len, retlen);
err = 2;
@@ -201,7 +183,8 @@ chfs_check_td_data(struct chfs_mount *chmp,
return 1;
}
nref->nref_offset = CHFS_GET_OFS(nref->nref_offset) | CHFS_NORMAL_NODE_MASK;
/* Correct sizes. */
CHFS_MARK_REF_NORMAL(nref);
totlen = CHFS_PAD(sizeof(struct chfs_flash_data_node) + len);
mutex_enter(&chmp->chm_lock_sizes);
@@ -216,6 +199,7 @@ out:
return err;
}
/* chfs_check_td_node - checks a temporary node */
int
chfs_check_td_node(struct chfs_mount *chmp, struct chfs_tmp_dnode *td)
{
@@ -225,13 +209,13 @@ chfs_check_td_node(struct chfs_mount *chmp, struct chfs_tmp_dnode *td)
return 0;
ret = chfs_check_td_data(chmp, td);
if (ret == 1) {
chfs_mark_node_obsolete(chmp, td->node->nref);
}
return ret;
}
/*
* chfs_first_valid_data_ref -
* returns the first valid nref after the given nref
*/
struct chfs_node_ref *
chfs_first_valid_data_ref(struct chfs_node_ref *nref)
{
@@ -253,13 +237,19 @@ chfs_first_valid_data_ref(struct chfs_node_ref *nref)
return NULL;
}
/*
* chfs_add_tmp_dnode_to_tdi -
* adds a temporary node to a temporary node descriptor
*/
void
chfs_add_tmp_dnode_to_tdi(struct chfs_tmp_dnode_info *tdi,
struct chfs_tmp_dnode *td)
{
if (!tdi->tmpnode) {
/* The chain is empty. */
tdi->tmpnode = td;
} else {
/* Insert into the chain. */
struct chfs_tmp_dnode *tmp = tdi->tmpnode;
while (tmp->next) {
tmp = tmp->next;
@@ -268,13 +258,19 @@ chfs_add_tmp_dnode_to_tdi(struct chfs_tmp_dnode_info *tdi,
}
}
/*
* chfs_remove_tmp_dnode_from_tdi -
* removes a temporary node from its descriptor
*/
void
chfs_remove_tmp_dnode_from_tdi(struct chfs_tmp_dnode_info *tdi,
struct chfs_tmp_dnode *td)
{
if (tdi->tmpnode == td) {
/* It's the first in the chain. */
tdi->tmpnode = tdi->tmpnode->next;
} else {
/* Remove from the middle of the chain. */
struct chfs_tmp_dnode *tmp = tdi->tmpnode->next;
while (tmp->next && tmp->next != td) {
tmp = tmp->next;
@@ -285,24 +281,31 @@ chfs_remove_tmp_dnode_from_tdi(struct chfs_tmp_dnode_info *tdi,
}
}
/* chfs_kill_td - removes all components of a temporary node */
static void
chfs_kill_td(struct chfs_mount *chmp,
struct chfs_tmp_dnode *td)
{
/* check if we need to mark as obsolete, to avoid double mark */
if (!CHFS_REF_OBSOLETE(td->node->nref)) {
chfs_mark_node_obsolete(chmp, td->node->nref);
struct chfs_vnode_cache *vc;
if (td->node) {
mutex_enter(&chmp->chm_lock_vnocache);
/* Remove the node from the vnode cache's data node chain. */
vc = chfs_nref_to_vc(td->node->nref);
chfs_remove_and_obsolete(chmp, vc, td->node->nref, &vc->dnode);
mutex_exit(&chmp->chm_lock_vnocache);
}
chfs_free_tmp_dnode(td);
}
/* chfs_kill_tdi - removes a temporary node descriptor */
static void
chfs_kill_tdi(struct chfs_mount *chmp,
struct chfs_tmp_dnode_info *tdi)
{
struct chfs_tmp_dnode *next, *tmp = tdi->tmpnode;
/* Iterate the chain and remove all temporary node from it. */
while (tmp) {
next = tmp->next;
chfs_kill_td(chmp, tmp);
@@ -312,6 +315,10 @@ chfs_kill_tdi(struct chfs_mount *chmp,
chfs_free_tmp_dnode_info(tdi);
}
/*
* chfs_add_tmp_dnode_to_tree -
* adds a temporary node to the temporary tree
*/
int
chfs_add_tmp_dnode_to_tree(struct chfs_mount *chmp,
struct chfs_readinode_info *rii,
@@ -335,6 +342,7 @@ chfs_add_tmp_dnode_to_tree(struct chfs_mount *chmp,
this = (struct chfs_tmp_dnode_info *)node;
}
}
while (node) {
this = (struct chfs_tmp_dnode_info *)node;
if (this->tmpnode->node->ofs > end_ofs)
@@ -343,6 +351,7 @@ chfs_add_tmp_dnode_to_tree(struct chfs_mount *chmp,
struct chfs_tmp_dnode *tmp_td = this->tmpnode;
while (tmp_td) {
if (tmp_td->version == newtd->version) {
/* This is a new version of an old node. */
if (!chfs_check_td_node(chmp, tmp_td)) {
dbg("calling kill td 0\n");
chfs_kill_td(chmp, newtd);
@@ -422,8 +431,8 @@ chfs_add_tmp_dnode_to_tree(struct chfs_mount *chmp,
obsoleted by an earlier node. Insert into the tree */
struct chfs_tmp_dnode_info *tmp_tdi = rb_tree_insert_node(&rii->tdi_root, newtdi);
if (tmp_tdi != newtdi) {
chfs_remove_tmp_dnode_from_tdi(newtdi, newtd);
chfs_add_tmp_dnode_to_tdi(tmp_tdi, newtd);
newtdi->tmpnode = NULL;
chfs_kill_tdi(chmp, newtdi);
}
@@ -459,26 +468,30 @@ chfs_add_tmp_dnode_to_tree(struct chfs_mount *chmp,
}
/*
* --------------------
* frag node operations
* --------------------
*/
/* new_fragment - creates a new fragment for a data node */
struct chfs_node_frag *
new_fragment(struct chfs_full_dnode *fdn, uint32_t ofs, uint32_t size)
{
struct chfs_node_frag *newfrag;
newfrag = chfs_alloc_node_frag();
if (newfrag) {
/* Initialize fragment. */
newfrag->ofs = ofs;
newfrag->size = size;
newfrag->node = fdn;
if (newfrag->node) {
newfrag->node->frags++;
}
} else {
chfs_err("cannot allocate a chfs_node_frag object\n");
}
return newfrag;
}
/*
* no_overlapping_node - inserts a node to the fragtree
* Puts hole frag into the holes between fragments.
*/
int
no_overlapping_node(struct rb_tree *fragtree,
struct chfs_node_frag *newfrag,
@@ -494,7 +507,6 @@ no_overlapping_node(struct rb_tree *fragtree,
}
rb_tree_insert_node(fragtree, holefrag);
this = holefrag;
}
rb_tree_insert_node(fragtree, newfrag);
@@ -502,6 +514,10 @@ no_overlapping_node(struct rb_tree *fragtree,
return 0;
}
/*
* chfs_add_frag_to_fragtree -
* adds a fragment to a data node's fragtree
*/
int
chfs_add_frag_to_fragtree(struct chfs_mount *chmp,
struct rb_tree *fragtree,
@@ -511,6 +527,7 @@ chfs_add_frag_to_fragtree(struct chfs_mount *chmp,
uint32_t lastend;
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
/* Find the offset of frag which is before the new one. */
this = (struct chfs_node_frag *)rb_tree_find_node_leq(fragtree, &newfrag->ofs);
if (this) {
@@ -519,8 +536,8 @@ chfs_add_frag_to_fragtree(struct chfs_mount *chmp,
lastend = 0;
}
/* New fragment is end of the file and there is no overlapping. */
if (lastend <= newfrag->ofs) {
//dbg("no overlapping node\n");
if (lastend && (lastend - 1) >> PAGE_SHIFT == newfrag->ofs >> PAGE_SHIFT) {
if (this->node)
CHFS_MARK_REF_NORMAL(this->node->nref);
@@ -530,22 +547,18 @@ chfs_add_frag_to_fragtree(struct chfs_mount *chmp,
}
if (newfrag->ofs > this->ofs) {
CHFS_MARK_REF_NORMAL(newfrag->node->nref);
if (this->node)
CHFS_MARK_REF_NORMAL(this->node->nref);
if (this->ofs + this->size > newfrag->ofs + newfrag->size) {
/* newfrag is inside of this */
//dbg("newfrag is inside of this\n");
/* Newfrag is inside of this. */
struct chfs_node_frag *newfrag2;
newfrag2 = new_fragment(this->node, newfrag->ofs + newfrag->size,
this->ofs + this->size - newfrag->ofs - newfrag->size);
if (!newfrag2)
return ENOMEM;
if (this->node)
this->node->frags++;
this->size = newfrag->ofs - this->ofs;
@@ -554,13 +567,11 @@ chfs_add_frag_to_fragtree(struct chfs_mount *chmp,
return 0;
}
/* newfrag is bottom of this */
//dbg("newfrag is bottom of this\n");
/* Newfrag is bottom of this. */
this->size = newfrag->ofs - this->ofs;
rb_tree_insert_node(fragtree, newfrag);
} else {
/* newfrag start at same point */
//dbg("newfrag start at same point\n");
/* Newfrag start at same point */
//TODO replace instead of remove and insert
rb_tree_remove_node(fragtree, this);
rb_tree_insert_node(fragtree, newfrag);
@@ -596,30 +607,60 @@ chfs_add_frag_to_fragtree(struct chfs_mount *chmp,
return 0;
}
/*
* chfs_remove_frags_of_node -
* removes all fragments from a fragtree and DOESN'T OBSOLETE them
*/
void
chfs_kill_fragtree(struct rb_tree *fragtree)
chfs_remove_frags_of_node(struct chfs_mount *chmp, struct rb_tree *fragtree,
struct chfs_node_ref *nref)
{
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
struct chfs_node_frag *this, *next;
//dbg("start\n");
if (nref == NULL) {
return;
}
/* Iterate the tree and clean all elements. */
this = (struct chfs_node_frag *)RB_TREE_MIN(fragtree);
while (this) {
//for (this = (struct chfs_node_frag *)RB_TREE_MIN(&fragtree); this != NULL; this = (struct chfs_node_frag *)rb_tree_iterate(&fragtree, &this->rb_node, RB_DIR_RIGHT)) {
next = frag_next(fragtree, this);
rb_tree_remove_node(fragtree, this);
chfs_free_node_frag(this);
//dbg("one frag killed\n");
if (this->node->nref == nref) {
rb_tree_remove_node(fragtree, this);
chfs_free_node_frag(this);
}
this = next;
}
//dbg("end\n");
}
/*
* chfs_kill_fragtree -
* removes all fragments from a fragtree and OBSOLETES them
*/
void
chfs_kill_fragtree(struct chfs_mount *chmp, struct rb_tree *fragtree)
{
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
struct chfs_node_frag *this, *next;
/* Iterate the tree and clean all elements. */
this = (struct chfs_node_frag *)RB_TREE_MIN(fragtree);
while (this) {
next = frag_next(fragtree, this);
rb_tree_remove_node(fragtree, this);
chfs_obsolete_node_frag(chmp, this);
this = next;
}
}
/* chfs_truncate_fragtree - truncates the tree to a specified size */
uint32_t
chfs_truncate_fragtree(struct chfs_mount *chmp,
struct rb_tree *fragtree, uint32_t size)
{
struct chfs_node_frag *frag;
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
struct chfs_node_frag *frag;
dbg("truncate to size: %u\n", size);
@@ -658,45 +699,45 @@ chfs_truncate_fragtree(struct chfs_mount *chmp,
/* FIXME Should we check the postion of the last node? (PAGE_CACHE size, etc.) */
if (frag->node && (frag->ofs & (PAGE_SIZE - 1)) == 0) {
frag->node->nref->nref_offset = CHFS_GET_OFS(frag->node->nref->nref_offset) | CHFS_PRISTINE_NODE_MASK;
frag->node->nref->nref_offset =
CHFS_GET_OFS(frag->node->nref->nref_offset) | CHFS_PRISTINE_NODE_MASK;
}
return size;
}
/* chfs_obsolete_node_frag - obsoletes a fragment of a node */
void
chfs_obsolete_node_frag(struct chfs_mount *chmp,
struct chfs_node_frag *this)
{
struct chfs_vnode_cache *vc;
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
if (this->node) {
/* The fragment is in a node. */
KASSERT(this->node->frags != 0);
this->node->frags--;
if (!this->node->frags) {
struct chfs_vnode_cache *vc = chfs_nref_to_vc(this->node->nref);
chfs_mark_node_obsolete(chmp, this->node->nref);
if (vc->dnode == this->node->nref) {
vc->dnode = this->node->nref->nref_next;
} else {
struct chfs_node_ref *tmp = vc->dnode;
while (tmp->nref_next != (struct chfs_node_ref*) vc
&& tmp->nref_next != this->node->nref) {
tmp = tmp->nref_next;
}
if (tmp->nref_next == this->node->nref) {
tmp->nref_next = this->node->nref->nref_next;
}
// FIXME should we free here the this->node->nref?
}
if (this->node->frags == 0) {
/* This is the last fragment. (There is no more.) */
KASSERT(!CHFS_REF_OBSOLETE(this->node->nref));
mutex_enter(&chmp->chm_lock_vnocache);
vc = chfs_nref_to_vc(this->node->nref);
dbg("[MARK] lnr: %u ofs: %u\n", this->node->nref->nref_lnr,
this->node->nref->nref_offset);
chfs_remove_and_obsolete(chmp, vc, this->node->nref, &vc->dnode);
mutex_exit(&chmp->chm_lock_vnocache);
chfs_free_full_dnode(this->node);
} else {
/* There is more frags in the node. */
CHFS_MARK_REF_NORMAL(this->node->nref);
}
}
chfs_free_node_frag(this);
}
/* chfs_add_full_dnode_to_inode - adds a data node to an inode */
int
chfs_add_full_dnode_to_inode(struct chfs_mount *chmp,
struct chfs_inode *ip,
@@ -709,16 +750,16 @@ chfs_add_full_dnode_to_inode(struct chfs_mount *chmp,
if (unlikely(!fd->size))
return 0;
/* Create a new fragment from the data node and add it to the fragtree. */
newfrag = new_fragment(fd, fd->ofs, fd->size);
if (unlikely(!newfrag))
return ENOMEM;
newfrag->node->frags = 1;
ret = chfs_add_frag_to_fragtree(chmp, &ip->fragtree, newfrag);
if (ret)
return ret;
/* Check previous fragment. */
if (newfrag->ofs & (PAGE_SIZE - 1)) {
struct chfs_node_frag *prev = frag_prev(&ip->fragtree, newfrag);
@@ -727,6 +768,7 @@ chfs_add_full_dnode_to_inode(struct chfs_mount *chmp,
CHFS_MARK_REF_NORMAL(prev->node->nref);
}
/* Check next fragment. */
if ((newfrag->ofs+newfrag->size) & (PAGE_SIZE - 1)) {
struct chfs_node_frag *next = frag_next(&ip->fragtree, newfrag);
@@ -741,12 +783,7 @@ chfs_add_full_dnode_to_inode(struct chfs_mount *chmp,
}
/*
* -----------------------
* general node operations
* -----------------------
*/
/* get tmp nodes of an inode */
/* chfs_get_data_nodes - get temporary nodes of an inode */
int
chfs_get_data_nodes(struct chfs_mount *chmp,
struct chfs_inode *ip,
@@ -769,6 +806,7 @@ chfs_get_data_nodes(struct chfs_mount *chmp,
nref = chfs_first_valid_data_ref(ip->chvc->dnode);
/* Update highest version. */
rii->highest_version = ip->chvc->highest_version;
while(nref && (struct chfs_vnode_cache *)nref != ip->chvc) {
@@ -777,29 +815,33 @@ chfs_get_data_nodes(struct chfs_mount *chmp,
goto out;
dnode = (struct chfs_flash_data_node*)buf;
//check header crc
/* Check header crc. */
crc = crc32(0, (uint8_t *)dnode, CHFS_NODE_HDR_SIZE - 4);
if (crc != le32toh(dnode->hdr_crc)) {
chfs_err("CRC check failed. calc: 0x%x orig: 0x%x\n", crc, le32toh(dnode->hdr_crc));
goto cont;
}
//check header magic bitmask
/* Check header magic bitmask. */
if (le16toh(dnode->magic) != CHFS_FS_MAGIC_BITMASK) {
chfs_err("Wrong magic bitmask.\n");
goto cont;
}
//check node crc
/* Check node crc. */
crc = crc32(0, (uint8_t *)dnode, sizeof(*dnode) - 4);
if (crc != le32toh(dnode->node_crc)) {
chfs_err("Node CRC check failed. calc: 0x%x orig: 0x%x\n", crc, le32toh(dnode->node_crc));
goto cont;
}
td = chfs_alloc_tmp_dnode();
if (!td) {
chfs_err("Can't allocate tmp dnode info.\n");
err = ENOMEM;
goto out;
}
/* We don't check data crc here, just add nodes to tmp frag tree, because
* we don't want to check nodes which have been overlapped by a new node
* with a higher version number.
@@ -815,12 +857,14 @@ chfs_get_data_nodes(struct chfs_mount *chmp,
td->data_crc = le32toh(dnode->data_crc);
td->node->nref = nref;
td->node->size = le32toh(dnode->data_length);
td->node->frags = 1;
td->overlapped = 0;
if (td->version > rii->highest_version) {
rii->highest_version = td->version;
}
/* Add node to the tree. */
err = chfs_add_tmp_dnode_to_tree(chmp, rii, td);
if (err)
goto out_full_dnode;
@@ -832,7 +876,6 @@ cont:
ip->chvc->highest_version = rii->highest_version;
return 0;
/* Exit points */
out_full_dnode:
chfs_free_full_dnode(td->node);
out_tmp_dnode:
@@ -844,28 +887,31 @@ out:
}
/* Build final normal fragtree from tdi tree. */
/* chfs_build_fragtree - builds fragtree from temporary tree */
int
chfs_build_fragtree(struct chfs_mount *chmp, struct chfs_inode *ip,
struct chfs_readinode_info *rii)
{
struct chfs_tmp_dnode_info *pen, *last, *this;
struct rb_tree ver_tree; /* version tree */
struct rb_tree ver_tree; /* version tree, used only temporary */
uint64_t high_ver = 0;
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
rb_tree_init(&ver_tree, &tmp_node_rbtree_ops);
/* Update highest version and latest node reference. */
if (rii->mdata_tn) {
high_ver = rii->mdata_tn->tmpnode->version;
rii->latest_ref = rii->mdata_tn->tmpnode->node->nref;
}
/* Iterate the temporary tree in reverse order. */
pen = (struct chfs_tmp_dnode_info *)RB_TREE_MAX(&rii->tdi_root);
while((last = pen)) {
pen = (struct chfs_tmp_dnode_info *)rb_tree_iterate(&rii->tdi_root, last, RB_DIR_LEFT);
/* We build here a version tree from overlapped nodes. */
rb_tree_remove_node(&rii->tdi_root, last);
rb_tree_insert_node(&ver_tree, last);
@@ -878,6 +924,7 @@ chfs_build_fragtree(struct chfs_mount *chmp, struct chfs_inode *ip,
this = (struct chfs_tmp_dnode_info *)RB_TREE_MAX(&ver_tree);
/* Start to build the fragtree. */
while (this) {
struct chfs_tmp_dnode_info *vers_next;
int ret;
@@ -889,9 +936,11 @@ chfs_build_fragtree(struct chfs_mount *chmp, struct chfs_inode *ip,
while (tmp_td) {
struct chfs_tmp_dnode *next_td = tmp_td->next;
/* Check temporary node. */
if (chfs_check_td_node(chmp, tmp_td)) {
if (next_td) {
chfs_remove_tmp_dnode_from_tdi(this, tmp_td);
chfs_kill_td(chmp, tmp_td);
} else {
break;
}
@@ -902,19 +951,18 @@ chfs_build_fragtree(struct chfs_mount *chmp, struct chfs_inode *ip,
rii->latest_ref = tmp_td->node->nref;
}
/* Add node to inode and its fragtree. */
ret = chfs_add_full_dnode_to_inode(chmp, ip, tmp_td->node);
if (ret) {
/* On error, clean the whole version tree. */
while (1) {
vers_next = (struct chfs_tmp_dnode_info *)rb_tree_iterate(&ver_tree, this, RB_DIR_LEFT);
while (tmp_td) {
next_td = tmp_td->next;
if (chfs_check_td_node(chmp, tmp_td) > 1) {
chfs_mark_node_obsolete(chmp,
tmp_td->node->nref);
}
chfs_free_full_dnode(tmp_td->node);
chfs_remove_tmp_dnode_from_tdi(this, tmp_td);
chfs_free_tmp_dnode(tmp_td);
chfs_kill_td(chmp, tmp_td);
tmp_td = next_td;
}
chfs_free_tmp_dnode_info(this);
@@ -922,15 +970,20 @@ chfs_build_fragtree(struct chfs_mount *chmp, struct chfs_inode *ip,
if (!this)
break;
rb_tree_remove_node(&ver_tree, vers_next);
chfs_kill_tdi(chmp, vers_next);
}
return ret;
}
/* Remove temporary node from temporary descriptor.
* Shouldn't obsolete tmp_td here, because tmp_td->node
* was added to the inode. */
chfs_remove_tmp_dnode_from_tdi(this, tmp_td);
chfs_free_tmp_dnode(tmp_td);
}
tmp_td = next_td;
}
/* Continue with the previous element of version tree. */
chfs_kill_tdi(chmp, this);
this = vers_next;
}
@@ -939,6 +992,7 @@ chfs_build_fragtree(struct chfs_mount *chmp, struct chfs_inode *ip,
return 0;
}
/* chfs_read_inode - checks the state of the inode then reads and builds it */
int chfs_read_inode(struct chfs_mount *chmp, struct chfs_inode *ip)
{
struct chfs_vnode_cache *vc = ip->chvc;
@@ -946,39 +1000,38 @@ int chfs_read_inode(struct chfs_mount *chmp, struct chfs_inode *ip)
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
retry:
/* XXX locking */
//mutex_enter(&chmp->chm_lock_vnocache);
mutex_enter(&chmp->chm_lock_vnocache);
switch (vc->state) {
case VNO_STATE_UNCHECKED:
case VNO_STATE_CHECKEDABSENT:
// chfs_vnode_cache_set_state(chmp, vc, VNO_STATE_READING);
vc->state = VNO_STATE_READING;
break;
case VNO_STATE_CHECKING:
case VNO_STATE_GC:
//sleep_on_spinunlock(&chmp->chm_lock_vnocache);
//KASSERT(!mutex_owned(&chmp->chm_lock_vnocache));
goto retry;
break;
case VNO_STATE_PRESENT:
case VNO_STATE_READING:
chfs_err("Reading inode #%llu in state %d!\n",
(unsigned long long)vc->vno, vc->state);
chfs_err("wants to read a nonexistent ino %llu\n",
(unsigned long long)vc->vno);
return ENOENT;
default:
panic("BUG() Bad vno cache state.");
case VNO_STATE_UNCHECKED:
/* FALLTHROUGH */
case VNO_STATE_CHECKEDABSENT:
vc->state = VNO_STATE_READING;
break;
case VNO_STATE_CHECKING:
/* FALLTHROUGH */
case VNO_STATE_GC:
mutex_exit(&chmp->chm_lock_vnocache);
goto retry;
break;
case VNO_STATE_PRESENT:
/* FALLTHROUGH */
case VNO_STATE_READING:
chfs_err("Reading inode #%llu in state %d!\n",
(unsigned long long)vc->vno, vc->state);
chfs_err("wants to read a nonexistent ino %llu\n",
(unsigned long long)vc->vno);
return ENOENT;
default:
panic("BUG() Bad vno cache state.");
}
//mutex_exit(&chmp->chm_lock_vnocache);
mutex_exit(&chmp->chm_lock_vnocache);
return chfs_read_inode_internal(chmp, ip);
}
/*
* Read inode frags.
* Firstly get tmp nodes,
* secondly build fragtree from those.
* chfs_read_inode_internal - reads and builds an inode
* Firstly get temporary nodes then build fragtree.
*/
int
chfs_read_inode_internal(struct chfs_mount *chmp, struct chfs_inode *ip)
@@ -997,7 +1050,7 @@ chfs_read_inode_internal(struct chfs_mount *chmp, struct chfs_inode *ip)
rb_tree_init(&rii.tdi_root, &tmp_node_rbtree_ops);
/* build up a temp node frag tree */
/* Build a temporary node tree. */
err = chfs_get_data_nodes(chmp, ip, &rii);
if (err) {
if (ip->chvc->state == VNO_STATE_READING)
@@ -1006,10 +1059,9 @@ chfs_read_inode_internal(struct chfs_mount *chmp, struct chfs_inode *ip)
return err;
}
/* Build fragtree from temp nodes. */
rb_tree_init(&ip->fragtree, &frag_rbtree_ops);
/*
* build fragtree from temp nodes
*/
err = chfs_build_fragtree(chmp, ip, &rii);
if (err) {
if (ip->chvc->state == VNO_STATE_READING)
@@ -1026,9 +1078,7 @@ chfs_read_inode_internal(struct chfs_mount *chmp, struct chfs_inode *ip)
if (!buf)
return ENOMEM;
/*
* set inode size from chvc->v
*/
/* Set inode size from its vnode information node. */
err = chfs_read_leb(chmp, ip->chvc->v->nref_lnr, buf, CHFS_GET_OFS(ip->chvc->v->nref_offset), len, &retlen);
if (err || retlen != len) {
kmem_free(buf, len);
@@ -1053,6 +1103,7 @@ chfs_read_inode_internal(struct chfs_mount *chmp, struct chfs_inode *ip)
return 0;
}
/* chfs_read_data - reads and checks data of a file */
int
chfs_read_data(struct chfs_mount* chmp, struct vnode *vp,
struct buf *bp)
@@ -1069,10 +1120,12 @@ chfs_read_data(struct chfs_mount* chmp, struct vnode *vp,
memset(bp->b_data, 0, bp->b_bcount);
/* Calculate the size of the file from its fragtree. */
ofs = bp->b_blkno * PAGE_SIZE;
frag = (struct chfs_node_frag *)rb_tree_find_node_leq(&ip->fragtree, &ofs);
if (!frag || frag->ofs > ofs || frag->ofs + frag->size <= ofs) {
bp->b_resid = 0;
dbg("not found in frag tree\n");
return 0;
}
@@ -1083,11 +1136,11 @@ chfs_read_data(struct chfs_mount* chmp, struct vnode *vp,
}
nref = frag->node->nref;
size = sizeof(*dnode) + frag->size;
buf = kmem_alloc(size, KM_SLEEP);
/* Read node from flash. */
dbg("reading from lnr: %u, offset: %u, size: %zu\n", nref->nref_lnr, CHFS_GET_OFS(nref->nref_offset), size);
err = chfs_read_leb(chmp, nref->nref_lnr, buf, CHFS_GET_OFS(nref->nref_offset), size, &retlen);
if (err) {
@@ -1100,6 +1153,7 @@ chfs_read_data(struct chfs_mount* chmp, struct vnode *vp,
goto out;
}
/* Read data from flash. */
dnode = (struct chfs_flash_data_node *)buf;
crc = crc32(0, (uint8_t *)dnode, CHFS_NODE_HDR_SIZE - 4);
if (crc != le32toh(dnode->hdr_crc)) {
@@ -1107,19 +1161,23 @@ chfs_read_data(struct chfs_mount* chmp, struct vnode *vp,
err = EIO;
goto out;
}
//check header magic bitmask
/* Check header magic bitmask. */
if (le16toh(dnode->magic) != CHFS_FS_MAGIC_BITMASK) {
chfs_err("Wrong magic bitmask.\n");
err = EIO;
goto out;
}
//check node crc
/* Check crc of node. */
crc = crc32(0, (uint8_t *)dnode, sizeof(*dnode) - 4);
if (crc != le32toh(dnode->node_crc)) {
chfs_err("Node CRC check failed. calc: 0x%x orig: 0x%x\n", crc, le32toh(dnode->node_crc));
err = EIO;
goto out;
}
/* Check crc of data. */
crc = crc32(0, (uint8_t *)dnode->data, dnode->data_length);
if (crc != le32toh(dnode->data_crc)) {
chfs_err("Data CRC check failed. calc: 0x%x orig: 0x%x\n", crc, le32toh(dnode->data_crc));
+56 -201
View File
@@ -1,4 +1,4 @@
/* $NetBSD: chfs_scan.c,v 1.2 2011/11/24 21:09:37 agc Exp $ */
/* $NetBSD: chfs_scan.c,v 1.4 2012/10/19 12:44:39 ttoth Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
@@ -31,19 +31,10 @@
* 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 *
@@ -53,36 +44,33 @@ chfs_scan_make_vnode_cache(struct chfs_mount *chmp, ino_t vno)
KASSERT(mutex_owned(&chmp->chm_lock_vnocache));
/* vnode cache already exists */
vc = chfs_vnode_cache_get(chmp, vno);
if (vc) {
return vc;
}
/* update max vnode number if needed */
if (vno > chmp->chm_max_vno) {
chmp->chm_max_vno = vno;
}
/* create new vnode cache */
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);
vc->state = 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
@@ -109,13 +97,7 @@ chfs_scan_check_node_hdr(struct chfs_flash_node_hdr *nhdr)
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
*/
/* chfs_scan_check_vnode - check vnode crc and add it to vnode cache */
int
chfs_scan_check_vnode(struct chfs_mount *chmp,
struct chfs_eraseblock *cheb, void *buf, off_t ofs)
@@ -131,6 +113,7 @@ chfs_scan_check_vnode(struct chfs_mount *chmp,
crc = crc32(0, (uint8_t *)vnode,
sizeof(struct chfs_flash_vnode) - 4);
/* check node crc */
if (crc != le32toh(vnode->node_crc)) {
err = chfs_update_eb_dirty(chmp,
cheb, le32toh(vnode->length));
@@ -143,6 +126,7 @@ chfs_scan_check_vnode(struct chfs_mount *chmp,
vno = le64toh(vnode->vno);
/* find the corresponding vnode cache */
mutex_enter(&chmp->chm_lock_vnocache);
vc = chfs_vnode_cache_get(chmp, vno);
if (!vc) {
@@ -152,7 +136,6 @@ chfs_scan_check_vnode(struct chfs_mount *chmp,
return ENOMEM;
}
}
mutex_exit(&chmp->chm_lock_vnocache);
nref = chfs_alloc_node_ref(cheb);
@@ -160,11 +143,9 @@ chfs_scan_check_vnode(struct chfs_mount *chmp,
KASSERT(nref->nref_lnr == cheb->lnr);
/* Check version of vnode. */
/* 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 {
@@ -179,9 +160,10 @@ chfs_scan_check_vnode(struct chfs_mount *chmp,
*vc->vno_version = le64toh(vnode->version);
chfs_add_vnode_ref_to_vc(chmp, vc, nref);
}
mutex_exit(&chmp->chm_lock_vnocache);
/* update sizes */
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);
@@ -190,65 +172,33 @@ chfs_scan_check_vnode(struct chfs_mount *chmp,
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;
}
/* chfs_scan_mark_dirent_obsolete - marks a directory entry "obsolete" */
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 */
/* 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) {
while (prev->nref_next && prev->nref_next != (void *)vc) {
if (prev->nref_next == nref) {
prev->nref_next = nref->nref_next;
break;
}
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);
@@ -256,6 +206,7 @@ chfs_scan_mark_dirent_obsolete(struct chfs_mount *chmp,
return 0;
}
/* chfs_add_fd_to_list - adds a directory entry to its parent's vnode cache */
void
chfs_add_fd_to_list(struct chfs_mount *chmp,
struct chfs_dirent *new, struct chfs_vnode_cache *pvc)
@@ -263,11 +214,11 @@ chfs_add_fd_to_list(struct chfs_mount *chmp,
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);
/* update highest version if needed */
if ((new->version > pvc->highest_version))
pvc->highest_version = new->version;
@@ -284,7 +235,6 @@ chfs_add_fd_to_list(struct chfs_mount *chmp,
} 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);
@@ -299,26 +249,13 @@ chfs_add_fd_to_list(struct chfs_mount *chmp,
chfs_change_size_dirty(chmp, oldcheb, size);
}
chfs_free_dirent(fd);
// *prev = new;//XXX
} else {
/* new dirent is older */
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;
}
@@ -327,38 +264,17 @@ chfs_add_fd_to_list(struct chfs_mount *chmp,
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);
/* update sizes */
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
*/
/* chfs_scan_check_dirent_node - check vnode crc and add to vnode cache */
int
chfs_scan_check_dirent_node(struct chfs_mount *chmp,
struct chfs_eraseblock *cheb, void *buf, off_t ofs)
@@ -366,11 +282,10 @@ chfs_scan_check_dirent_node(struct chfs_mount *chmp,
int err, namelen;
uint32_t crc;
struct chfs_dirent *fd;
struct chfs_vnode_cache *vc;
struct chfs_vnode_cache *parentvc;
struct chfs_flash_dirent_node *dirent = buf;
//struct chfs_node_ref *tmp;
/* check crc */
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));
@@ -378,12 +293,15 @@ chfs_scan_check_dirent_node(struct chfs_mount *chmp,
return err;
return CHFS_NODE_BADCRC;
}
/* allocate space for name */
namelen = dirent->nsize;
fd = chfs_alloc_dirent(namelen + 1);
if (!fd)
return ENOMEM;
/* allocate an nref */
fd->nref = chfs_alloc_node_ref(cheb);
if (!fd->nref)
return ENOMEM;
@@ -404,79 +322,31 @@ chfs_scan_check_dirent_node(struct chfs_mount *chmp,
return CHFS_NODE_BADNAMECRC;
}
/* Check vnode_cache of parent node */
/* 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) {
parentvc = chfs_scan_make_vnode_cache(chmp, le64toh(dirent->pvno));
if (!parentvc) {
chfs_free_dirent(fd);
return ENOMEM;
}
fd->nref->nref_offset = ofs;
dbg("add dirent to #%llu\n", (unsigned long long)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);*/
dbg("add dirent to #%llu\n", (unsigned long long)parentvc->vno);
chfs_add_node_to_list(chmp, parentvc, fd->nref, &parentvc->dirents);
mutex_exit(&chmp->chm_lock_vnocache);
// 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);*/
chfs_add_fd_to_list(chmp, fd, parentvc);
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
*/
/* chfs_scan_check_data_node - check vnode crc and add to vnode cache */
int
chfs_scan_check_data_node(struct chfs_mount *chmp,
struct chfs_eraseblock *cheb, void *buf, off_t ofs)
@@ -488,6 +358,7 @@ chfs_scan_check_data_node(struct chfs_mount *chmp,
struct chfs_vnode_cache *vc;
struct chfs_flash_data_node *dnode = buf;
/* check crc */
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));
@@ -495,7 +366,7 @@ chfs_scan_check_data_node(struct chfs_mount *chmp,
return err;
return CHFS_NODE_BADCRC;
}
/**
/*
* Don't check data nodes crc and version here, it will be done in
* the background GC thread.
*/
@@ -503,7 +374,7 @@ chfs_scan_check_data_node(struct chfs_mount *chmp,
if (!nref)
return ENOMEM;
nref->nref_offset = ofs | CHFS_UNCHECKED_NODE_MASK;
nref->nref_offset = CHFS_GET_OFS(ofs) | CHFS_UNCHECKED_NODE_MASK;
KASSERT(nref->nref_lnr == cheb->lnr);
@@ -515,11 +386,12 @@ chfs_scan_check_data_node(struct chfs_mount *chmp,
if (!vc)
return ENOMEM;
}
mutex_exit(&chmp->chm_lock_vnocache);
chfs_add_node_to_list(chmp, vc, nref, &vc->dnode);
mutex_exit(&chmp->chm_lock_vnocache);
dbg("chmpfree: %u, chebfree: %u, dnode: %u\n", chmp->chm_free_size, cheb->free_size, dnode->length);
/* update sizes */
mutex_enter(&chmp->chm_lock_sizes);
chfs_change_size_free(chmp, cheb, -dnode->length);
chfs_change_size_unchecked(chmp, cheb, dnode->length);
@@ -527,11 +399,7 @@ chfs_scan_check_data_node(struct chfs_mount *chmp,
return CHFS_NODE_OK;
}
/**
* chfs_scan_classify_cheb - determine eraseblock's state
* @chmp: CHFS main descriptor structure
* @cheb: eraseblock to classify
*/
/* chfs_scan_classify_cheb - determine eraseblock's state */
int
chfs_scan_classify_cheb(struct chfs_mount *chmp,
struct chfs_eraseblock *cheb)
@@ -547,10 +415,8 @@ chfs_scan_classify_cheb(struct chfs_mount *chmp,
}
/**
/*
* 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.
@@ -558,8 +424,8 @@ chfs_scan_classify_cheb(struct chfs_mount *chmp,
*/
int
chfs_scan_eraseblock(struct chfs_mount *chmp,
struct chfs_eraseblock *cheb) {
struct chfs_eraseblock *cheb)
{
int err;
size_t len, retlen;
off_t ofs = 0;
@@ -569,7 +435,6 @@ chfs_scan_eraseblock(struct chfs_mount *chmp,
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);
@@ -591,7 +456,7 @@ chfs_scan_eraseblock(struct chfs_mount *chmp,
/* 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*/
* 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)) {
@@ -625,8 +490,8 @@ chfs_scan_eraseblock(struct chfs_mount *chmp,
}
switch (le16toh(nhdr->type)) {
case CHFS_NODETYPE_VNODE:
/* Read up the node */
//dbg("nodetype vnode\n");
/* vnode information */
/* read up the node */
len = le32toh(nhdr->length) - CHFS_NODE_HDR_SIZE;
err = chfs_read_leb(chmp,
lnr, buf + CHFS_NODE_HDR_SIZE,
@@ -647,11 +512,10 @@ chfs_scan_eraseblock(struct chfs_mount *chmp,
return err;
}
//dbg("XXX5end\n");
break;
case CHFS_NODETYPE_DIRENT:
/* Read up the node */
//dbg("nodetype dirent\n");
/* directory entry */
/* read up the node */
len = le32toh(nhdr->length) - CHFS_NODE_HDR_SIZE;
err = chfs_read_leb(chmp,
@@ -675,10 +539,9 @@ chfs_scan_eraseblock(struct chfs_mount *chmp,
return err;
}
//dbg("XXX6end\n");
break;
case CHFS_NODETYPE_DATA:
//dbg("nodetype data\n");
/* data node */
len = sizeof(struct chfs_flash_data_node) -
CHFS_NODE_HDR_SIZE;
err = chfs_read_leb(chmp,
@@ -699,12 +562,9 @@ chfs_scan_eraseblock(struct chfs_mount *chmp,
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);
/* padding node, set size and update dirty */
nref = chfs_alloc_node_ref(cheb);
nref->nref_offset = ofs - CHFS_NODE_HDR_SIZE;
nref->nref_offset = CHFS_GET_OFS(nref->nref_offset) |
@@ -712,21 +572,17 @@ chfs_scan_eraseblock(struct chfs_mount *chmp,
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 */
/* 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;
@@ -735,6 +591,5 @@ chfs_scan_eraseblock(struct chfs_mount *chmp,
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);
}
+59 -247
View File
@@ -1,4 +1,4 @@
/* $NetBSD: chfs_subr.c,v 1.2 2011/11/24 21:09:37 agc Exp $ */
/* $NetBSD: chfs_subr.c,v 1.9 2013/10/20 17:18:38 christos Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
@@ -32,10 +32,6 @@
* SUCH DAMAGE.
*/
/*
* Efficient memory file system supporting functions.
*/
#include <sys/cdefs.h>
#include <sys/param.h>
@@ -56,13 +52,12 @@
#include <uvm/uvm.h>
#include <miscfs/specfs/specdev.h>
#include <miscfs/genfs/genfs.h>
#include "chfs.h"
//#include <fs/chfs/chfs_vnops.h>
//#include </root/xipffs/netbsd.chfs/chfs.h>
/* --------------------------------------------------------------------- */
/*
* chfs_mem_info -
* Returns information about the number of available memory pages,
* including physical and virtual ones.
*
@@ -96,9 +91,8 @@ chfs_mem_info(bool total)
}
/* --------------------------------------------------------------------- */
/*
* chfs_dir_lookup -
* 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
@@ -116,40 +110,30 @@ chfs_dir_lookup(struct chfs_inode *ip, struct componentname *cnp)
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;
}
/* --------------------------------------------------------------------- */
/*
* chfs_filldir -
* Creates a (kernel) dirent and moves it to the given memory address.
* Used during readdir.
*/
int
chfs_filldir(struct uio* uio, ino_t ino, const char *name,
int namelen, enum vtype type)
int namelen, enum chtype type)
{
struct dirent dent;
int error;
@@ -158,31 +142,31 @@ chfs_filldir(struct uio* uio, ino_t ino, const char *name,
dent.d_fileno = ino;
switch (type) {
case VBLK:
case CHT_BLK:
dent.d_type = DT_BLK;
break;
case VCHR:
case CHT_CHR:
dent.d_type = DT_CHR;
break;
case VDIR:
case CHT_DIR:
dent.d_type = DT_DIR;
break;
case VFIFO:
case CHT_FIFO:
dent.d_type = DT_FIFO;
break;
case VLNK:
case CHT_LNK:
dent.d_type = DT_LNK;
break;
case VREG:
case CHT_REG:
dent.d_type = DT_REG;
break;
case VSOCK:
case CHT_SOCK:
dent.d_type = DT_SOCK;
break;
@@ -202,11 +186,8 @@ chfs_filldir(struct uio* uio, ino_t ino, const char *name,
return error;
}
/* --------------------------------------------------------------------- */
/*
* Change size of the given vnode.
* chfs_chsize - 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.
*/
@@ -215,28 +196,23 @@ 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:
switch (ip->ch_type) {
case CHT_DIR:
return EISDIR;
case VLNK:
case VREG:
case CHT_LNK:
case CHT_REG:
if (vp->v_mount->mnt_flag & MNT_RDONLY)
return EROFS;
break;
case VBLK:
case VCHR:
case VFIFO:
case CHT_BLK:
case CHT_CHR:
case CHT_FIFO:
return 0;
default:
return EOPNOTSUPP; /* XXX why not ENODEV? */
@@ -245,190 +221,71 @@ chfs_chsize(struct vnode *vp, u_quad_t size, kauth_cred_t cred)
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);
if (ip->size < size) {
uvm_vnp_setsize(vp, size);
chfs_set_vnode_size(vp, size);
ip->iflag |= IN_CHANGE | IN_UPDATE;
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",
(unsigned long long)size, (unsigned long long)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;
if (size != 0) {
ubc_zerorange(&vp->v_uobj, size, ip->size - size, UBC_UNMAP_FLAG(vp));
}
/* drop unused fragments */
chfs_truncate_fragtree(ip->chmp, &ip->fragtree, size);
uvm_vnp_setsize(vp, size);
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);
}
ip->iflag |= IN_CHANGE | IN_UPDATE;
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.
* chfs_chflags - 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;
kauth_action_t action = KAUTH_VNODE_WRITE_FLAGS;
bool changing_sysflags = false;
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)))
if ((flags & SF_SNAPSHOT) != (ip->flags & SF_SNAPSHOT))
return EPERM;
/* Indicate we're changing system flags if we are. */
if ((ip->flags & SF_SETTABLE) != (flags & SF_SETTABLE) ||
(flags & UF_SETTABLE) != flags) {
action |= KAUTH_VNODE_WRITE_SYSFLAGS;
changing_sysflags = true;
}
/* Indicate the node has system flags if it does. */
if (ip->flags & (SF_IMMUTABLE | SF_APPEND)) {
action |= KAUTH_VNODE_HAS_SYSFLAGS;
}
error = kauth_authorize_vnode(cred, action, vp, NULL,
genfs_can_chflags(cred, CHTTOVT(ip->ch_type), ip->uid, changing_sysflags));
if (error)
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;
if (changing_sysflags) {
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);
}
@@ -443,13 +300,12 @@ chfs_chflags(struct vnode *vp, int flags, kauth_cred_t cred)
return error;
}
/* --------------------------------------------------------------------- */
/* chfs_itimes - updates a vnode times to the given data */
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))) {
@@ -466,7 +322,6 @@ chfs_itimes(struct chfs_inode *ip, const struct timespec *acc,
if (mod == NULL)
mod = &now;
ip->mtime = mod->tv_sec;
//ip->i_modrev++;
}
if (ip->iflag & (IN_CHANGE | IN_MODIFY)) {
if (cre == NULL)
@@ -480,61 +335,18 @@ chfs_itimes(struct chfs_inode *ip, const struct timespec *acc,
ip->iflag &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY);
}
/* --------------------------------------------------------------------- */
/* chfs_update - updates a vnode times */
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;
}*/
+85 -105
View File
@@ -1,4 +1,4 @@
/* $NetBSD: chfs_vfsops.c,v 1.2 2011/11/24 21:09:37 agc Exp $ */
/* $NetBSD: chfs_vfsops.c,v 1.9 2013/10/20 17:18:38 christos Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
@@ -56,13 +56,10 @@
#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"
@@ -103,13 +100,6 @@ const struct genfs_ops chfs_genfsops = {
.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 */
@@ -158,17 +148,13 @@ chfs_mount(struct mount *mp,
if (err) {
return err;
}
/*
* Look up the name and verify that it's sane.
*/
/* 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
*/
/* Be sure this is a valid block device */
if (devvp->v_type != VBLK)
err = ENOTBLK;
else if (bdevsw_lookup(devvp->v_rdev) == NULL)
@@ -189,7 +175,7 @@ chfs_mount(struct mount *mp,
if (err)
goto fail;
/* call CHFS mount function */
err = chfs_mountfs(devvp, mp);
if (err) {
vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
@@ -197,6 +183,7 @@ chfs_mount(struct mount *mp,
VOP_UNLOCK(devvp);
goto fail;
}
ump = VFSTOUFS(mp);
chmp = ump->um_chfs;
@@ -212,12 +199,11 @@ fail:
return (err);
}
/* chfs_mountfs - init CHFS */
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;
@@ -229,7 +215,6 @@ chfs_mountfs(struct vnode *devvp, struct mount *mp)
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. */
@@ -239,6 +224,7 @@ chfs_mountfs(struct vnode *devvp, struct mount *mp)
if (err)
return (err);
/* Setup device. */
flash_major = cdevsw_lookup_major(&flash_cdevsw);
if (devvp->v_type != VBLK)
@@ -255,53 +241,40 @@ chfs_mountfs(struct vnode *devvp, struct mount *mp)
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));
/* Connect CHFS to UFS. */
ump = kmem_zalloc(sizeof(struct ufsmount), KM_SLEEP);
ump->um_fstype = UFS1;
ump->um_chfs = kmem_zalloc(sizeof(struct chfs_mount), KM_SLEEP);
mutex_init(&ump->um_lock, MUTEX_DEFAULT, IPL_NONE);
/* Get superblock and set flash device number */
chmp = ump->um_chfs;
if (!chmp)
return ENOMEM;
/* Initialize erase block handler. */
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;
goto fail;
}
//TODO check flash sizes
/* Initialize vnode cache's hashtable and eraseblock array. */
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;
}
/* Initialize mutexes. */
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
/* Initialize read/write contants. (from UFS) */
chmp->chm_fs_bmask = -4096;
chmp->chm_fs_bsize = 4096;
chmp->chm_fs_qbmask = 4095;
@@ -309,12 +282,13 @@ chfs_mountfs(struct vnode *devvp, struct mount *mp)
chmp->chm_fs_fmask = -2048;
chmp->chm_fs_qfmask = 2047;
/* Initialize writebuffer. */
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
/* Initialize queues. */
TAILQ_INIT(&chmp->chm_free_queue);
TAILQ_INIT(&chmp->chm_clean_queue);
TAILQ_INIT(&chmp->chm_dirty_queue);
@@ -322,8 +296,10 @@ chfs_mountfs(struct vnode *devvp, struct mount *mp)
TAILQ_INIT(&chmp->chm_erasable_pending_wbuf_queue);
TAILQ_INIT(&chmp->chm_erase_pending_queue);
/* Initialize flash-specific constants. */
chfs_calc_trigger_levels(chmp);
/* Initialize sizes. */
chmp->chm_nr_free_blocks = 0;
chmp->chm_nr_erasable_blocks = 0;
chmp->chm_max_vno = 2;
@@ -333,17 +309,19 @@ chfs_mountfs(struct vnode *devvp, struct mount *mp)
chmp->chm_dirty_size = 0;
chmp->chm_wasted_size = 0;
chmp->chm_free_size = chmp->chm_ebh->eb_size * chmp->chm_ebh->peb_nr;
/* Build filesystem. */
err = chfs_build_filesystem(chmp);
if (err) {
/* Armageddon and return. */
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;
err = EIO;
goto fail;
}
/* Initialize UFS. */
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);
@@ -358,19 +336,8 @@ chfs_mountfs(struct vnode *devvp, struct mount *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.
*/
/* Allocate the root vnode. */
err = VFS_VGET(mp, CHFS_ROOTINO, &vp);
if (err) {
dbg("error: %d while allocating root node\n", err);
@@ -378,25 +345,30 @@ chfs_mountfs(struct vnode *devvp, struct mount *mp)
}
vput(vp);
/* Start GC. */
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;
spec_node_setmountedfs(devvp, mp);
return 0;
fail:
kmem_free(chmp->chm_ebh, sizeof(struct chfs_ebh));
kmem_free(chmp, sizeof(struct chfs_mount));
kmem_free(ump, sizeof(struct ufsmount));
return err;
}
/* --------------------------------------------------------------------- */
/* 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;
@@ -406,8 +378,10 @@ chfs_unmount(struct mount *mp, int mntflags)
ump = VFSTOUFS(mp);
chmp = ump->um_chfs;
/* Stop GC. */
chfs_gc_thread_stop(chmp);
/* Flush everyt buffer. */
(void)vflush(mp, NULLVP, flags);
if (chmp->chm_wbuf_len) {
@@ -416,21 +390,26 @@ chfs_unmount(struct mount *mp, int mntflags)
mutex_exit(&chmp->chm_lock_mountfields);
}
/* Free node references. */
for (i = 0; i < chmp->chm_ebh->peb_nr; i++) {
chfs_free_node_refs(&chmp->chm_blocks[i]);
}
/* Destroy vnode cache hashtable. */
chfs_vnocache_hash_destroy(chmp->chm_vnocache_hash);
/* Close eraseblock handler. */
ebh_close(chmp->chm_ebh);
/* Destroy mutexes. */
rw_destroy(&chmp->chm_lock_wbuf);
mutex_destroy(&chmp->chm_lock_vnocache);
mutex_destroy(&chmp->chm_lock_sizes);
mutex_destroy(&chmp->chm_lock_mountfields);
/* Unmount UFS. */
if (ump->um_devvp->v_type != VBAD) {
ump->um_devvp->v_specmountpoint = NULL;
spec_node_setmountedfs(ump->um_devvp, NULL);
}
vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY);
(void)VOP_CLOSE(ump->um_devvp, FREAD|FWRITE, NOCRED);
@@ -438,8 +417,8 @@ chfs_unmount(struct mount *mp, int mntflags)
mutex_destroy(&ump->um_lock);
//free(ump->um_chfs, M_UFSMNT);
free(ump, M_UFSMNT);
/* Everything done. */
kmem_free(ump, sizeof(struct ufsmount));
mp->mnt_data = NULL;
mp->mnt_flag &= ~MNT_LOCAL;
dbg("[END]\n");
@@ -454,7 +433,7 @@ chfs_root(struct mount *mp, struct vnode **vpp)
struct vnode *vp;
int error;
if ((error = VFS_VGET(mp, (ino_t)ROOTINO, &vp)) != 0)
if ((error = VFS_VGET(mp, (ino_t)UFS_ROOTINO, &vp)) != 0)
return error;
*vpp = vp;
return 0;
@@ -486,6 +465,7 @@ retry:
vpp = kmem_alloc(sizeof(struct vnode*), KM_SLEEP);
}
/* Get node from inode hash. */
if ((*vpp = chfs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL) {
return 0;
}
@@ -508,9 +488,11 @@ retry:
vp->v_vflag |= VV_LOCKSWORK;
/* Initialize vnode/inode. */
memset(ip, 0, sizeof(*ip));
vp->v_data = ip;
ip->vp = vp;
ip->ch_type = VTTOCHT(vp->v_type);
ip->ump = ump;
ip->chmp = chmp = ump->um_chfs;
ip->dev = dev;
@@ -519,38 +501,36 @@ retry:
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
/* Set root inode. */
if (ino == CHFS_ROOTINO) {
dbg("SETROOT\n");
vp->v_vflag |= VV_ROOT;
vp->v_type = VDIR;
ip->ch_type = CHT_DIR;
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");
/* Initialize the corresponding vnode cache. */
/* 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);
chvc->state = VNO_STATE_CHECKEDABSENT;
}
chfs_vnode_cache_add(chmp, chvc);
mutex_exit(&chmp->chm_lock_vnocache);
@@ -560,7 +540,7 @@ retry:
} else {
dbg("chvc\n");
ip->chvc = chvc;
// if we have a vnode cache, the node is already on flash, so read it
/* We had 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);
@@ -569,9 +549,10 @@ retry:
}
mutex_enter(&chmp->chm_lock_mountfields);
// init type specific things
switch (vp->v_type) {
case VDIR:
/* Initialize type specific things. */
switch (ip->ch_type) {
case CHT_DIR:
/* Read every dirent. */
nref = chvc->dirents;
while (nref &&
(struct chfs_vnode_cache *)nref != chvc) {
@@ -580,9 +561,10 @@ retry:
}
chfs_set_vnode_size(vp, 512);
break;
case VREG:
case VSOCK:
//build the fragtree of the vnode
case CHT_REG:
/* FALLTHROUGH */
case CHT_SOCK:
/* Collect data. */
dbg("read_inode_internal | ino: %llu\n",
(unsigned long long)ip->ino);
error = chfs_read_inode(chmp, ip);
@@ -593,8 +575,8 @@ retry:
return (error);
}
break;
case VLNK:
//build the fragtree of the vnode
case CHT_LNK:
/* Collect data. */
dbg("read_inode_internal | ino: %llu\n",
(unsigned long long)ip->ino);
error = chfs_read_inode_internal(chmp, ip);
@@ -605,6 +587,7 @@ retry:
return (error);
}
/* Set link. */
dbg("size: %llu\n", (unsigned long long)ip->size);
bp = getiobuf(vp, true);
bp->b_blkno = 0;
@@ -620,10 +603,12 @@ retry:
putiobuf(bp);
break;
case VCHR:
case VBLK:
case VFIFO:
//build the fragtree of the vnode
case CHT_CHR:
/* FALLTHROUGH */
case CHT_BLK:
/* FALLTHROUGH */
case CHT_FIFO:
/* Collect data. */
dbg("read_inode_internal | ino: %llu\n",
(unsigned long long)ip->ino);
error = chfs_read_inode_internal(chmp, ip);
@@ -634,6 +619,7 @@ retry:
return (error);
}
/* Set device. */
bp = getiobuf(vp, true);
bp->b_blkno = 0;
bp->b_bufsize = bp->b_resid =
@@ -644,23 +630,25 @@ retry:
bp->b_data, sizeof(dev_t));
kmem_free(bp->b_data, sizeof(dev_t));
putiobuf(bp);
if (vp->v_type == VFIFO)
/* Set specific operations. */
if (ip->ch_type == CHT_FIFO) {
vp->v_op = chfs_fifoop_p;
else {
} else {
vp->v_op = chfs_specop_p;
spec_node_init(vp, ip->rdev);
}
break;
case VNON:
case VBAD:
case CHT_BLANK:
/* FALLTHROUGH */
case CHT_BAD:
break;
}
mutex_exit(&chmp->chm_lock_mountfields);
}
/* finish inode initalization */
/* Finish inode initalization. */
ip->devvp = ump->um_devvp;
vref(ip->devvp);
@@ -696,7 +684,6 @@ chfs_start(struct mount *mp, int flags)
/* --------------------------------------------------------------------- */
/* ARGSUSED2 */
static int
chfs_statvfs(struct mount *mp, struct statvfs *sbp)
{
@@ -715,14 +702,6 @@ chfs_statvfs(struct mount *mp, struct statvfs *sbp)
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;
@@ -739,7 +718,6 @@ chfs_statvfs(struct mount *mp, struct statvfs *sbp)
/* --------------------------------------------------------------------- */
/* ARGSUSED0 */
static int
chfs_sync(struct mount *mp, int waitfor,
kauth_cred_t uc)
@@ -752,6 +730,7 @@ chfs_sync(struct mount *mp, int waitfor,
static void
chfs_init(void)
{
/* Initialize pools and inode hash. */
chfs_alloc_pool_caches();
chfs_ihashinit();
pool_init(&chfs_inode_pool, sizeof(struct chfs_inode), 0, 0, 0,
@@ -812,7 +791,7 @@ struct vfsops chfs_vfsops = {
chfs_start, /* vfs_start */
chfs_unmount, /* vfs_unmount */
chfs_root, /* vfs_root */
ufs_quotactl, /* vfs_quotactl */
ufs_quotactl, /* vfs_quotactl */
chfs_statvfs, /* vfs_statvfs */
chfs_sync, /* vfs_sync */
chfs_vget, /* vfs_vget */
@@ -823,16 +802,17 @@ struct vfsops chfs_vfsops = {
chfs_done, /* vfs_done */
NULL, /* vfs_mountroot */
chfs_snapshot, /* vfs_snapshot */
vfs_stdextattrctl, /* vfs_extattrctl */
(void *)eopnotsupp, /* vfs_suspendctl */
vfs_stdextattrctl, /* vfs_extattrctl */
(void *)eopnotsupp, /* vfs_suspendctl */
genfs_renamelock_enter,
genfs_renamelock_exit,
(void *)eopnotsupp,
chfs_vnodeopv_descs,
0, /* vfs_refcount */
0, /* vfs_refcount */
{ NULL, NULL },
};
/* For using CHFS as a module. */
static int
chfs_modcmd(modcmd_t cmd, void *arg)
{
+76 -56
View File
@@ -1,4 +1,4 @@
/* $NetBSD: chfs_vnode.c,v 1.2 2011/11/24 21:09:37 agc Exp $ */
/* $NetBSD: chfs_vnode.c,v 1.8 2012/10/19 12:44:39 ttoth Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
@@ -40,6 +40,9 @@
#include <sys/uio.h>
#include <sys/buf.h>
#include <miscfs/genfs/genfs.h>
/* chfs_vnode_lookup - lookup for a vnode */
struct vnode *
chfs_vnode_lookup(struct chfs_mount *chmp, ino_t vno)
{
@@ -54,8 +57,9 @@ chfs_vnode_lookup(struct chfs_mount *chmp, ino_t vno)
return NULL;
}
/* chfs_readvnode - reads a vnode from the flash and setups its inode */
int
chfs_readvnode(struct mount* mp, ino_t ino, struct vnode** vpp)
chfs_readvnode(struct mount *mp, ino_t ino, struct vnode **vpp)
{
struct ufsmount* ump = VFSTOUFS(mp);
struct chfs_mount *chmp = ump->um_chfs;
@@ -79,13 +83,14 @@ chfs_readvnode(struct mount* mp, ino_t ino, struct vnode** vpp)
ip = VTOI(vp);
chvc = ip->chvc;
/* root node is in-memory only */
if (chvc && ino != CHFS_ROOTINO) {
/* debug... */
printf("readvnode; offset: %" PRIu32 ", lnr: %d\n",
dbg("offset: %" PRIu32 ", lnr: %d\n",
CHFS_GET_OFS(chvc->v->nref_offset), chvc->v->nref_lnr);
KASSERT((void *)chvc != (void *)chvc->v);
/* reading */
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);
@@ -97,16 +102,19 @@ chfs_readvnode(struct mount* mp, ino_t ino, struct vnode** vpp)
return EIO;
}
chfvn = (struct chfs_flash_vnode*)buf;
/* setup inode fields */
chfs_set_vnode_size(vp, chfvn->dn_size);
ip->mode = chfvn->mode;
vp->v_type = IFTOVT(ip->mode);
ip->ch_type = IFTOCHT(ip->mode);
vp->v_type = CHTTOVT(ip->ch_type);
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);
}
@@ -115,21 +123,22 @@ chfs_readvnode(struct mount* mp, ino_t ino, struct vnode** vpp)
return 0;
}
/*
* chfs_readddirent -
* reads a directory entry from flash and adds it to its inode
*/
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;
struct chfs_dirent *fd;
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
/* read flash_dirent_node */
err = chfs_read_leb(chmp, chnr->nref_lnr, (char *)&chfdn,
CHFS_GET_OFS(chnr->nref_offset), len, &retlen);
if (err) {
@@ -141,14 +150,14 @@ chfs_readdirent(struct mount *mp, struct chfs_node_ref *chnr, struct chfs_inode
return EIO;
}
//set fields of dirent
/* 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;
/* read the name of the dirent */
err = chfs_read_leb(chmp, chnr->nref_lnr, fd->name,
CHFS_GET_OFS(chnr->nref_offset) + len, chfdn.nsize, &retlen);
if (err) {
@@ -164,51 +173,40 @@ chfs_readdirent(struct mount *mp, struct chfs_node_ref *chnr, struct chfs_inode
fd->name[fd->nsize] = 0;
fd->nref = chnr;
/* add to inode */
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.
*/
/* chfs_makeinode - makes a new file and initializes its structures */
int
chfs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
struct componentname *cnp, int type)
struct componentname *cnp, enum vtype 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;
int error;
ino_t vno;
struct chfs_dirent *nfd;//, *fd;
struct chfs_dirent *nfd;
dbg("makeinode\n");
pdir = VTOI(dvp);
*vpp = NULL;
/* number of vnode will be the new maximum */
vno = ++(chmp->chm_max_vno);
error = VFS_VGET(dvp->v_mount, vno, &vp);
if (error)
return (error);
/* setup vnode cache */
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);
@@ -217,9 +215,10 @@ chfs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
chvc->nlink = 1;
else
chvc->nlink = 2;
// chfs_vnode_cache_set_state(chmp, chvc, VNO_STATE_CHECKEDABSENT);
chvc->state = VNO_STATE_CHECKEDABSENT;
mutex_exit(&chmp->chm_lock_vnocache);
/* setup inode */
ip = VTOI(vp);
ip->ino = vno;
@@ -234,21 +233,26 @@ chfs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
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;
vp->v_type = type; /* Rest init'd in getnewvnode(). */
ip->ch_type = VTTOCHT(vp->v_type);
/* authorize setting SGID if needed */
if (ip->mode & ISGID) {
error = kauth_authorize_vnode(cnp->cn_cred, KAUTH_VNODE_WRITE_SECURITY,
vp, NULL, genfs_can_chmod(vp->v_type, cnp->cn_cred, ip->uid,
ip->gid, mode));
if (error)
ip->mode &= ~ISGID;
}
/* write vnode information to the flash */
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);
@@ -256,7 +260,8 @@ chfs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
vput(dvp);
return error;
}
//update parent directory and write it to the flash
/* update parent's vnode information and write it to the flash */
pdir->iflag |= (IN_ACCESS | IN_CHANGE | IN_MODIFY | IN_UPDATE);
chfs_update(dvp, NULL, NULL, UPDATE_WAIT);
@@ -269,18 +274,17 @@ chfs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
}
vput(dvp);
//set up node's full dirent
/* setup directory entry */
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->type = ip->ch_type;
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
/* write out */
error = chfs_write_flash_dirent(chmp, pdir, ip, nfd, ip->ino, ALLOC_NORMAL);
if (error) {
mutex_exit(&chmp->chm_lock_mountfields);
@@ -290,19 +294,9 @@ chfs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
//TODO set parent's dir times
/* add dirent to parent */
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);
@@ -311,6 +305,7 @@ chfs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
return (0);
}
/* chfs_set_vnode_size - updates size of vnode and also inode */
void
chfs_set_vnode_size(struct vnode *vp, size_t size)
{
@@ -326,6 +321,11 @@ chfs_set_vnode_size(struct vnode *vp, size_t size)
return;
}
/*
* chfs_change_size_free - updates free size
* "change" parameter is positive if we have to increase the size
* and negative if we have to decrease it
*/
void
chfs_change_size_free(struct chfs_mount *chmp,
struct chfs_eraseblock *cheb, int change)
@@ -339,6 +339,11 @@ chfs_change_size_free(struct chfs_mount *chmp,
return;
}
/*
* chfs_change_size_dirty - updates dirty size
* "change" parameter is positive if we have to increase the size
* and negative if we have to decrease it
*/
void
chfs_change_size_dirty(struct chfs_mount *chmp,
struct chfs_eraseblock *cheb, int change)
@@ -352,6 +357,11 @@ chfs_change_size_dirty(struct chfs_mount *chmp,
return;
}
/*
* chfs_change_size_unchecked - updates unchecked size
* "change" parameter is positive if we have to increase the size
* and negative if we have to decrease it
*/
void
chfs_change_size_unchecked(struct chfs_mount *chmp,
struct chfs_eraseblock *cheb, int change)
@@ -365,6 +375,11 @@ chfs_change_size_unchecked(struct chfs_mount *chmp,
return;
}
/*
* chfs_change_size_used - updates used size
* "change" parameter is positive if we have to increase the size
* and negative if we have to decrease it
*/
void
chfs_change_size_used(struct chfs_mount *chmp,
struct chfs_eraseblock *cheb, int change)
@@ -378,6 +393,11 @@ chfs_change_size_used(struct chfs_mount *chmp,
return;
}
/*
* chfs_change_size_wasted - updates wasted size
* "change" parameter is positive if we have to increase the size
* and negative if we have to decrease it
*/
void
chfs_change_size_wasted(struct chfs_mount *chmp,
struct chfs_eraseblock *cheb, int change)
+10 -35
View File
@@ -1,4 +1,4 @@
/* $NetBSD: chfs_vnode_cache.c,v 1.1 2011/11/24 15:51:32 ahoka Exp $ */
/* $NetBSD: chfs_vnode_cache.c,v 1.3 2012/10/19 12:44:39 ttoth Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
@@ -35,6 +35,9 @@
#include "chfs.h"
#include <sys/pool.h>
/* vnode cache is a hashtable for vnodes */
/* chfs_vnocache_hash_init - initializing the hashtable */
struct chfs_vnode_cache **
chfs_vnocache_hash_init(void)
{
@@ -42,25 +45,8 @@ chfs_vnocache_hash_init(void)
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
/*
* chfs_vnode_cache_get - get a vnode_cache from the hashtable
* Returns the vnode_cache.
*/
struct chfs_vnode_cache *
@@ -87,11 +73,7 @@ chfs_vnode_cache_get(struct chfs_mount *chmp, ino_t vno)
return ret;
}
/**
* chfs_add_vnode_cache - add a vnode_cache to the vnocache_hash
* @chmp: fs super block info
* @new: new vnode_cache
*/
/* chfs_vnode_cache_add - add a vnode_cache to the hashtable */
void
chfs_vnode_cache_add(struct chfs_mount *chmp,
struct chfs_vnode_cache* new)
@@ -113,11 +95,7 @@ chfs_vnode_cache_add(struct chfs_mount *chmp,
*prev = new;
}
/**
* chfs_del_vnode_cache - del a vnode_cache from the vnocache_hash
* @chmp: fs super block info
* @old: old vnode_cache
*/
/* chfs_vnode_cache_remove - removes a vnode_cache from the hashtable */
void
chfs_vnode_cache_remove(struct chfs_mount *chmp,
struct chfs_vnode_cache* old)
@@ -141,16 +119,14 @@ chfs_vnode_cache_remove(struct chfs_mount *chmp,
}
}
/**
* chfs_free_vnode_caches - free the vnocache_hash
* @chmp: fs super block info
*/
/* chfs_vnocache_hash_destroy - destroying the vnode cache */
void
chfs_vnocache_hash_destroy(struct chfs_vnode_cache **hash)
{
struct chfs_vnode_cache *this, *next;
int i;
/* free every row */
for (i = 0; i < VNODECACHE_SIZE; i++) {
this = hash[i];
while (this) {
@@ -162,4 +138,3 @@ chfs_vnocache_hash_destroy(struct chfs_vnode_cache **hash)
}
}
+150 -156
View File
@@ -1,4 +1,4 @@
/* $NetBSD: chfs_vnops.c,v 1.2 2011/11/24 21:09:37 agc Exp $ */
/* $NetBSD: chfs_vnops.c,v 1.18 2013/10/20 17:18:38 christos Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
@@ -70,24 +70,25 @@ chfs_lookup(void *v)
*vpp = NULL;
// Check accessibility of requested node as a first step.
/* Check accessibility of requested node as a first step. */
error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred);
if (error != 0) {
goto out;
}
// If requesting the last path component on a read-only file system
// with a write operation, deny it.
/* If requesting the last path component on a read-only file system
* with a write operation, deny it. */
if ((cnp->cn_flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY)
&& (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
error = EROFS;
goto out;
}
// Avoid doing a linear scan of the directory if the requested
// directory/name couple is already in the cache.
error = cache_lookup(dvp, vpp, cnp);
if (error >= 0) {
/* Avoid doing a linear scan of the directory if the requested
* directory/name couple is already in the cache. */
if (cache_lookup(dvp, cnp->cn_nameptr, cnp->cn_namelen,
cnp->cn_nameiop, cnp->cn_flags, NULL, vpp)) {
error = *vpp == NULLVP ? ENOENT : 0;
goto out;
}
@@ -101,8 +102,8 @@ chfs_lookup(void *v)
chvc = chfs_vnode_cache_get(chmp, ip->ino);
mutex_exit(&chmp->chm_lock_vnocache);
// We cannot be requesting the parent directory of the root node.
KASSERT(IMPLIES(dvp->v_type == VDIR && chvc->pvno == chvc->vno,
/* We cannot be requesting the parent directory of the root node. */
KASSERT(IMPLIES(ip->ch_type == CHT_DIR && chvc->pvno == chvc->vno,
!(cnp->cn_flags & ISDOTDOT)));
if (cnp->cn_flags & ISDOTDOT) {
@@ -118,10 +119,10 @@ chfs_lookup(void *v)
if (fd == NULL) {
dbg("fd null\n");
// The entry was not found in the directory.
// This is OK if we are creating or renaming an
// entry and are working on the last component of
// the path name.
/* The entry was not found in the directory.
* This is OK if we are creating or renaming an
* entry and are working on the last component of
* the path name. */
if ((cnp->cn_flags & ISLASTCN) && (cnp->cn_nameiop == CREATE
|| cnp->cn_nameiop == RENAME)) {
error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred);
@@ -136,11 +137,11 @@ chfs_lookup(void *v)
error = ENOENT;
}
} else {
// If we are not at the last path component and
// found a non-directory or non-link entry (which
// may itself be pointing to a directory), raise
// an error.
if ((fd->type != VDIR && fd->type != VLNK) && !(cnp->cn_flags
/* If we are not at the last path component and
* found a non-directory or non-link entry (which
* may itself be pointing to a directory), raise
* an error. */
if ((fd->type != CHT_DIR && fd->type != CHT_LNK) && !(cnp->cn_flags
& ISLASTCN)) {
error = ENOTDIR;
goto out;
@@ -151,19 +152,18 @@ chfs_lookup(void *v)
error = VFS_VGET(dvp->v_mount, fd->vno, vpp);
}
}
// Store the result of this lookup in the cache. Avoid this if the
// request was for creation, as it does not improve timings on
// emprical tests.
if ((cnp->cn_flags & MAKEENTRY) && cnp->cn_nameiop != CREATE
&& (cnp->cn_flags & ISDOTDOT) == 0)
cache_enter(dvp, *vpp, cnp);
/* Store the result of this lookup in the cache. Avoid this if the
* request was for creation, as it does not improve timings on
* emprical tests. */
if (cnp->cn_nameiop != CREATE && (cnp->cn_flags & ISDOTDOT) == 0) {
cache_enter(dvp, *vpp, cnp->cn_nameptr, cnp->cn_namelen,
cnp->cn_flags);
}
out:
// If there were no errors, *vpp cannot be null and it must be
// locked.
/* If there were no errors, *vpp cannot be null and it must be
* locked. */
KASSERT(IFF(error == 0, *vpp != NULL && VOP_ISLOCKED(*vpp)));
// dvp must always be locked.
KASSERT(VOP_ISLOCKED(dvp));
return error;
@@ -217,7 +217,6 @@ chfs_mknod(void *v)
struct ufsmount *ump;
struct chfs_mount *chmp;
ino_t ino;
struct chfs_full_dnode *fd;
struct buf *bp;
@@ -227,6 +226,7 @@ chfs_mknod(void *v)
ump = VFSTOUFS(dvp->v_mount);
chmp = ump->um_chfs;
/* Check type of node. */
if (vap->va_type != VBLK && vap->va_type != VCHR && vap->va_type != VFIFO)
return EINVAL;
@@ -250,10 +250,10 @@ chfs_mknod(void *v)
}
}
/* Create a new node. */
err = chfs_makeinode(mode, dvp, &vp, cnp, vap->va_type);
ip = VTOI(vp);
ino = ip->ino;
if (vap->va_rdev != VNOVAL)
ip->rdev = vap->va_rdev;
@@ -267,6 +267,7 @@ chfs_mknod(void *v)
if (err)
return err;
/* Device is written out as a data node. */
len = sizeof(dev_t);
chfs_set_vnode_size(vp, len);
bp = getiobuf(vp, true);
@@ -286,6 +287,7 @@ chfs_mknod(void *v)
return err;
}
/* Add data node to the inode. */
err = chfs_add_full_dnode_to_inode(chmp, ip, fd);
if (err) {
mutex_exit(&chmp->chm_lock_mountfields);
@@ -324,7 +326,7 @@ chfs_open(void *v)
goto out;
}
// If the file is marked append-only, deny write requests.
/* If the file is marked append-only, deny write requests. */
if (ip->flags & APPEND && (mode & (FWRITE | O_APPEND)) == FWRITE)
error = EPERM;
else
@@ -350,7 +352,6 @@ chfs_close(void *v)
ip = VTOI(vp);
if (ip->chvc->nlink > 0) {
//ip->chvc->nlink = 0;
chfs_update(vp, NULL, NULL, UPDATE_CLOSE);
}
@@ -390,8 +391,9 @@ chfs_access(void *v)
if (mode & VWRITE && ip->flags & IMMUTABLE)
return (EPERM);
return genfs_can_access(vp->v_type, ip->mode & ALLPERMS,
ip->uid, ip->gid, mode, cred);
return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode, vp->v_type,
ip->mode & ALLPERMS), vp, NULL, genfs_can_access(vp->v_type,
ip->mode & ALLPERMS, ip->uid, ip->gid, mode, cred));
}
/* --------------------------------------------------------------------- */
@@ -410,7 +412,7 @@ chfs_getattr(void *v)
vattr_null(vap);
CHFS_ITIMES(ip, NULL, NULL, NULL);
vap->va_type = vp->v_type;
vap->va_type = CHTTOVT(ip->ch_type);
vap->va_mode = ip->mode & ALLPERMS;
vap->va_nlink = ip->chvc->nlink;
vap->va_uid = ip->uid;
@@ -466,26 +468,42 @@ chfs_setattr(void *v)
return EINVAL;
}
if (error == 0 && (vap->va_flags != VNOVAL))
/* set flags */
if (error == 0 && (vap->va_flags != VNOVAL)) {
error = chfs_chflags(vp, vap->va_flags, cred);
return error;
}
if (error == 0 && (vap->va_size != VNOVAL))
if (ip->flags & (IMMUTABLE | APPEND)) {
error = EPERM;
return error;
}
/* set size */
if (error == 0 && (vap->va_size != VNOVAL)) {
error = chfs_chsize(vp, vap->va_size, cred);
if (error)
return error;
}
if (error == 0 && (vap->va_uid != VNOVAL || vap->va_gid != VNOVAL))
/* set owner */
if (error == 0 && (vap->va_uid != VNOVAL || vap->va_gid != VNOVAL)) {
error = chfs_chown(vp, vap->va_uid, vap->va_gid, cred);
if (error)
return error;
}
if (error == 0 && (vap->va_mode != VNOVAL))
/* set mode */
if (error == 0 && (vap->va_mode != VNOVAL)) {
error = chfs_chmod(vp, vap->va_mode, cred);
if (error)
return error;
}
#if 0
/* why do we need that? */
if (ip->flags & (IMMUTABLE | APPEND))
return EPERM;
#endif
/* set time */
if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
error = genfs_can_chtimes(vp, vap->va_vaflags, ip->uid, cred);
error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
NULL, genfs_can_chtimes(vp, vap->va_vaflags, ip->uid, cred));
if (error)
return error;
if (vap->va_atime.tv_sec != VNOVAL)
@@ -498,6 +516,7 @@ chfs_setattr(void *v)
return error;
}
/* Write it out. */
mutex_enter(&chmp->chm_lock_mountfields);
error = chfs_write_flash_vnode(chmp, ip, ALLOC_NORMAL);
mutex_exit(&chmp->chm_lock_mountfields);
@@ -512,7 +531,8 @@ chfs_chmod(struct vnode *vp, int mode, kauth_cred_t cred)
int error;
dbg("chmod\n");
error = genfs_can_chmod(vp, cred, ip->uid, ip->gid, mode);
error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp,
NULL, genfs_can_chmod(vp->v_type, cred, ip->uid, ip->gid, mode));
if (error)
return error;
ip->mode &= ~ALLPERMS;
@@ -538,7 +558,8 @@ chfs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred)
if (gid == (gid_t)VNOVAL)
gid = ip->gid;
error = genfs_can_chown(vp, cred, ip->uid, ip->gid, uid, gid);
error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP, vp,
NULL, genfs_can_chown(cred, ip->uid, ip->gid, uid, gid));
if (error)
return error;
@@ -556,30 +577,31 @@ chfs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred)
/* --------------------------------------------------------------------- */
/* calculates ((off_t)blk * chmp->chm_chm_fs_bsize) */
#define lblktosize(chmp, blk) \
#define chfs_lblktosize(chmp, blk) \
(((off_t)(blk)) << (chmp)->chm_fs_bshift)
/* calculates (loc % chmp->chm_chm_fs_bsize) */
#define blkoff(chmp, loc) \
#define chfs_blkoff(chmp, loc) \
((loc) & (chmp)->chm_fs_qbmask)
/* calculates (loc / chmp->chm_chm_fs_bsize) */
#define lblkno(chmp, loc) \
#define chfs_lblkno(chmp, loc) \
((loc) >> (chmp)->chm_fs_bshift)
/* calculates roundup(size, chmp->chm_chm_fs_fsize) */
#define fragroundup(chmp, size) \
#define chfs_fragroundup(chmp, size) \
(((size) + (chmp)->chm_fs_qfmask) & (chmp)->chm_fs_fmask)
#define blksize(chmp, ip, lbn) \
(((lbn) >= NDADDR || (ip)->size >= lblktosize(chmp, (lbn) + 1)) \
#define chfs_blksize(chmp, ip, lbn) \
(((lbn) >= UFS_NDADDR || (ip)->size >= chfs_lblktosize(chmp, (lbn) + 1)) \
? (chmp)->chm_fs_bsize \
: (fragroundup(chmp, blkoff(chmp, (ip)->size))))
: (chfs_fragroundup(chmp, chfs_blkoff(chmp, (ip)->size))))
/* calculates roundup(size, chmp->chm_chm_fs_bsize) */
#define blkroundup(chmp, size) \
#define chfs_blkroundup(chmp, size) \
(((size) + (chmp)->chm_fs_qbmask) & (chmp)->chm_fs_bmask)
/* from ffs read */
int
chfs_read(void *v)
{
@@ -657,24 +679,23 @@ chfs_read(void *v)
goto out;
}
dbg("start reading\n");
for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
bytesinfile = ip->size - uio->uio_offset;
if (bytesinfile <= 0)
break;
lbn = lblkno(chmp, uio->uio_offset);
lbn = chfs_lblkno(chmp, uio->uio_offset);
nextlbn = lbn + 1;
size = blksize(chmp, ip, lbn);
blkoffset = blkoff(chmp, uio->uio_offset);
size = chfs_blksize(chmp, ip, lbn);
blkoffset = chfs_blkoff(chmp, uio->uio_offset);
xfersize = MIN(MIN(chmp->chm_fs_bsize - blkoffset, uio->uio_resid),
bytesinfile);
if (lblktosize(chmp, nextlbn) >= ip->size) {
if (chfs_lblktosize(chmp, nextlbn) >= ip->size) {
error = bread(vp, lbn, size, NOCRED, 0, &bp);
dbg("after bread\n");
} else {
int nextsize = blksize(chmp, ip, nextlbn);
int nextsize = chfs_blksize(chmp, ip, nextlbn);
dbg("size: %ld\n", size);
error = breadn(vp, lbn,
size, &nextlbn, &nextsize, 1, NOCRED, 0, &bp);
@@ -702,32 +723,35 @@ chfs_read(void *v)
break;
brelse(bp, 0);
}
if (bp != NULL)
brelse(bp, 0);
out:
// FIXME HACK
ip->ino = ip->chvc->vno;
if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) {
ip->iflag |= IN_ACCESS;
if ((ap->a_ioflag & IO_SYNC) == IO_SYNC) {
//error = UFS_WAPBL_BEGIN(vp->v_mount);
if (error) {
fstrans_done(vp->v_mount);
return error;
}
error = chfs_update(vp, NULL, NULL, UPDATE_WAIT);
//UFS_WAPBL_END(vp->v_mount);
}
}
dbg("[END]\n");
fstrans_done(vp->v_mount);
return (error);
}
/* --------------------------------------------------------------------- */
/*from ffs write*/
/* from ffs write */
int
chfs_write(void *v)
{
@@ -757,11 +781,8 @@ chfs_write(void *v)
uio = ap->a_uio;
vp = ap->a_vp;
ip = VTOI(vp);
//dbg("file size (vp): %llu\n", (unsigned long long)vp->v_size);
//dbg("file size (ip): %llu\n", (unsigned long long)ip->i_size);
ump = ip->ump;
//dbg("uio->resid: %d\n", uio->uio_resid);
dbg("write\n");
KASSERT(vp->v_size == ip->size);
@@ -810,7 +831,6 @@ chfs_write(void *v)
if (uio->uio_resid == 0)
return (0);
//mutex_enter(&ip->inode_lock);
fstrans_start(vp->v_mount, FSTRANS_SHARED);
flags = ioflag & IO_SYNC ? B_SYNC : 0;
@@ -820,32 +840,23 @@ chfs_write(void *v)
osize = ip->size;
error = 0;
/*if ((ioflag & IO_JOURNALLOCKED) == 0) {
error = UFS_WAPBL_BEGIN(vp->v_mount);
if (error) {
fstrans_done(vp->v_mount);
return error;
}
}*/
preallocoff = round_page(blkroundup(chmp,
preallocoff = round_page(chfs_blkroundup(chmp,
MAX(osize, uio->uio_offset)));
aflag = ioflag & IO_SYNC ? B_SYNC : 0;
nsize = MAX(osize, uio->uio_offset + uio->uio_resid);
endallocoff = nsize - blkoff(chmp, nsize);
endallocoff = nsize - chfs_blkoff(chmp, nsize);
/*
* if we're increasing the file size, deal with expanding
* the fragment if there is one.
*/
if (nsize > osize && lblkno(chmp, osize) < NDADDR &&
lblkno(chmp, osize) != lblkno(chmp, nsize) &&
blkroundup(chmp, osize) != osize) {
if (nsize > osize && chfs_lblkno(chmp, osize) < UFS_NDADDR &&
chfs_lblkno(chmp, osize) != chfs_lblkno(chmp, nsize) &&
chfs_blkroundup(chmp, osize) != osize) {
off_t eob;
eob = blkroundup(chmp, osize);
eob = chfs_blkroundup(chmp, osize);
uvm_vnp_setwritesize(vp, eob);
error = ufs_balloc_range(vp, osize, eob - osize, cred, aflag);
if (error)
@@ -869,7 +880,7 @@ chfs_write(void *v)
}
oldoff = uio->uio_offset;
blkoffset = blkoff(chmp, uio->uio_offset);
blkoffset = chfs_blkoff(chmp, uio->uio_offset);
bytelen = MIN(chmp->chm_fs_bsize - blkoffset, uio->uio_resid);
if (bytelen == 0) {
break;
@@ -885,12 +896,12 @@ chfs_write(void *v)
overwrite = uio->uio_offset >= preallocoff &&
uio->uio_offset < endallocoff;
if (!overwrite && (vp->v_vflag & VV_MAPPED) == 0 &&
blkoff(chmp, uio->uio_offset) == 0 &&
chfs_blkoff(chmp, uio->uio_offset) == 0 &&
(uio->uio_offset & PAGE_MASK) == 0) {
vsize_t len;
len = trunc_page(bytelen);
len -= blkoff(chmp, len);
len -= chfs_blkoff(chmp, len);
if (len > 0) {
overwrite = true;
bytelen = len;
@@ -959,13 +970,22 @@ out:
mutex_enter(vp->v_interlock);
error = VOP_PUTPAGES(vp,
trunc_page(origoff & chmp->chm_fs_bmask),
round_page(blkroundup(chmp, uio->uio_offset)),
round_page(chfs_blkroundup(chmp, uio->uio_offset)),
PGO_CLEANIT | PGO_SYNCIO | PGO_JOURNALLOCKED);
}
ip->iflag |= IN_CHANGE | IN_UPDATE;
if (resid > uio->uio_resid && ap->a_cred &&
kauth_authorize_generic(ap->a_cred, KAUTH_GENERIC_ISSUSER, NULL)) {
ip->mode &= ~(ISUID | ISGID);
if (resid > uio->uio_resid && ap->a_cred) {
if (ip->mode & ISUID) {
if (kauth_authorize_vnode(ap->a_cred,
KAUTH_VNODE_RETAIN_SUID, vp, NULL, EPERM) != 0)
ip->mode &= ~ISUID;
}
if (ip->mode & ISGID) {
if (kauth_authorize_vnode(ap->a_cred,
KAUTH_VNODE_RETAIN_SGID, vp, NULL, EPERM) != 0)
ip->mode &= ~ISGID;
}
}
if (resid > uio->uio_resid)
VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0));
@@ -976,12 +996,10 @@ out:
} else if (resid > uio->uio_resid && (ioflag & IO_SYNC) == IO_SYNC)
error = UFS_UPDATE(vp, NULL, NULL, UPDATE_WAIT);
//XXX hack, i write the next line after i know ip->i_size and vp->v_size don't equal
//FIXME HACK
chfs_set_vnode_size(vp, vp->v_size);
//dbg("end file size (vp): %llu\n", (unsigned long long)vp->v_size);
//dbg("end file size (ip): %llu\n", (unsigned long long)ip->i_size);
KASSERT(vp->v_size == ip->size);
fstrans_done(vp->v_mount);
@@ -989,8 +1007,6 @@ out:
error = chfs_write_flash_vnode(chmp, ip, ALLOC_NORMAL);
mutex_exit(&chmp->chm_lock_mountfields);
//mutex_exit(&ip->inode_lock);
//dbg("end\n");
return (error);
}
@@ -1000,7 +1016,6 @@ out:
int
chfs_fsync(void *v)
{
//dbg("fsync\n");
struct vop_fsync_args /* {
struct vnode *a_vp;
kauth_cred_t a_cred;
@@ -1009,15 +1024,11 @@ chfs_fsync(void *v)
off_t offhi;
} */ *ap = v;
struct vnode *vp = ap->a_vp;
int wait;
if (ap->a_flags & FSYNC_CACHE) {
return ENODEV;
}
wait = (ap->a_flags & FSYNC_WAIT) != 0;
vflushbuf(vp, wait);
//struct chfs_inode *ip = VTOI(vp);
//chfs_set_vnode_size(vp, ip->write_size);
vflushbuf(vp, ap->a_flags);
return 0;
}
@@ -1039,11 +1050,18 @@ chfs_remove(void *v)
struct chfs_inode *parent = VTOI(dvp);
int error = 0;
if (vp->v_type == VDIR || (ip->flags & (IMMUTABLE | APPEND)) ||
(parent->flags & APPEND)) {
error = EPERM;
goto out;
}
KASSERT(ip->chvc->vno != ip->chvc->pvno);
error = chfs_do_unlink(ip,
parent, cnp->cn_nameptr, cnp->cn_namelen);
out:
vput(dvp);
vput(vp);
@@ -1081,7 +1099,7 @@ chfs_link(void *v)
ip = VTOI(vp);
error = chfs_do_link(ip,
parent, cnp->cn_nameptr, cnp->cn_namelen, vp->v_type);
parent, cnp->cn_nameptr, cnp->cn_namelen, ip->ch_type);
if (dvp != vp)
VOP_UNLOCK(vp);
@@ -1104,7 +1122,7 @@ chfs_rename(void *v)
struct chfs_inode *oldparent, *old;
struct chfs_inode *newparent;
struct chfs_dirent *fd;//, *oldfd;
struct chfs_dirent *fd;
struct chfs_inode *ip;
int error = 0;
dbg("rename\n");
@@ -1119,18 +1137,12 @@ chfs_rename(void *v)
dbg("tvp not null\n");
ip = VTOI(tvp);
if (tvp->v_type == VDIR) {
//TODO: lock
// fd = ip->dents;
// while (fd) {
TAILQ_FOREACH(fd, &ip->dents, fds) {
if (fd->vno) {
//TODO: unlock
error = ENOTEMPTY;
goto out_unlocked;
}
// fd = fd->next;
}
//TODO: unlock
}
error = chfs_do_unlink(ip,
newparent, tcnp->cn_nameptr, tcnp->cn_namelen);
@@ -1139,21 +1151,15 @@ chfs_rename(void *v)
VFS_VGET(tdvp->v_mount, old->ino, &tvp);
ip = VTOI(tvp);
// for (oldfd = oldparent->dents;
// oldfd->vno != old->ino;
// oldfd = oldfd->next);
/* link new */
error = chfs_do_link(ip,
newparent, tcnp->cn_nameptr, tcnp->cn_namelen, tvp->v_type);
newparent, tcnp->cn_nameptr, tcnp->cn_namelen, ip->ch_type);
/* remove old */
error = chfs_do_unlink(old,
oldparent, fcnp->cn_nameptr, fcnp->cn_namelen);
//out:
// if (fchnode != tchnode)
// VOP_UNLOCK(fdvp, 0);
out_unlocked:
// Release target nodes.
/* Release target nodes. */
if (tdvp == tvp)
vrele(tdvp);
else
@@ -1161,7 +1167,7 @@ out_unlocked:
if (tvp != NULL)
vput(tvp);
// Release source nodes.
/* Release source nodes. */
vrele(fdvp);
vrele(fvp);
@@ -1216,7 +1222,6 @@ chfs_rmdir(void *v)
KASSERT(ip->chvc->vno != ip->chvc->pvno);
// for (fd = ip->dents; fd; fd = fd->next) {
TAILQ_FOREACH(fd, &ip->dents, fds) {
if (fd->vno) {
error = ENOTEMPTY;
@@ -1266,6 +1271,7 @@ chfs_symlink(void *v)
ip = VTOI(vp);
/* TODO max symlink len instead of "100" */
if (len < 100) {
/* symlink path stored as a data node */
ip->target = kmem_alloc(len, KM_SLEEP);
memcpy(ip->target, target, len);
chfs_set_vnode_size(vp, len);
@@ -1281,12 +1287,14 @@ chfs_symlink(void *v)
mutex_enter(&chmp->chm_lock_mountfields);
/* write out the data node */
err = chfs_write_flash_dnode(chmp, vp, bp, fd);
if (err) {
mutex_exit(&chmp->chm_lock_mountfields);
goto out;
}
/* add it to the inode */
err = chfs_add_full_dnode_to_inode(chmp, ip, fd);
if (err) {
mutex_exit(&chmp->chm_lock_mountfields);
@@ -1346,8 +1354,9 @@ chfs_readdir(void *v)
*/
offset = uio->uio_offset;
/* Add this entry. */
if (offset == CHFS_OFFSET_DOT) {
error = chfs_filldir(uio, ip->ino, ".", 1, VDIR);
error = chfs_filldir(uio, ip->ino, ".", 1, CHT_DIR);
if (error == -1) {
error = 0;
goto outok;
@@ -1357,6 +1366,7 @@ chfs_readdir(void *v)
offset = CHFS_OFFSET_DOTDOT;
}
/* Add parent entry. */
if (offset == CHFS_OFFSET_DOTDOT) {
ump = VFSTOUFS(vp->v_mount);
chmp = ump->um_chfs;
@@ -1364,7 +1374,7 @@ chfs_readdir(void *v)
chvc = chfs_vnode_cache_get(chmp, ip->ino);
mutex_exit(&chmp->chm_lock_vnocache);
error = chfs_filldir(uio, chvc->pvno, "..", 2, VDIR);
error = chfs_filldir(uio, chvc->pvno, "..", 2, CHT_DIR);
if (error == -1) {
error = 0;
goto outok;
@@ -1372,6 +1382,7 @@ chfs_readdir(void *v)
goto outok;
}
/* Has child or not? */
if (TAILQ_EMPTY(&ip->dents)) {
offset = CHFS_OFFSET_EOF;
} else {
@@ -1380,6 +1391,7 @@ chfs_readdir(void *v)
}
if (offset != CHFS_OFFSET_EOF) {
/* Child entries. */
skip = offset - CHFS_OFFSET_FIRST;
TAILQ_FOREACH(fd, &ip->dents, fds) {
@@ -1455,6 +1467,7 @@ chfs_inactive(void *v)
KASSERT(VOP_ISLOCKED(vp));
/* Reclaim only if there is no link to the node. */
if (ip->ino) {
chvc = ip->chvc;
if (chvc->nlink)
@@ -1479,28 +1492,24 @@ chfs_reclaim(void *v)
struct chfs_mount *chmp = ip->chmp;
struct chfs_dirent *fd;
//dbg("reclaim() | ino: %llu\n", (unsigned long long)ip->ino);
//mutex_enter(&ip->inode_lock);
mutex_enter(&chmp->chm_lock_mountfields);
mutex_enter(&chmp->chm_lock_vnocache);
chfs_vnode_cache_set_state(chmp,
ip->chvc, VNO_STATE_CHECKEDABSENT);
ip->chvc->state = VNO_STATE_CHECKEDABSENT;
mutex_exit(&chmp->chm_lock_vnocache);
chfs_update(vp, NULL, NULL, UPDATE_CLOSE);
if (vp->v_type == VREG || vp->v_type == VLNK || vp->v_type == VCHR ||
vp->v_type == VBLK || vp->v_type == VFIFO || vp->v_type == VSOCK)
chfs_kill_fragtree(&ip->fragtree);
/* Clean fragments. */
chfs_kill_fragtree(chmp, &ip->fragtree);
/* Clean dirents. */
fd = TAILQ_FIRST(&ip->dents);
while(fd) {
while (fd) {
TAILQ_REMOVE(&ip->dents, fd, fds);
chfs_free_dirent(fd);
fd = TAILQ_FIRST(&ip->dents);
}
//mutex_exit(&ip->inode_lock);
//mutex_destroy(&ip->inode_lock);
cache_purge(vp);
if (ip->devvp) {
@@ -1512,6 +1521,9 @@ chfs_reclaim(void *v)
genfs_node_destroy(vp);
pool_put(&chfs_inode_pool, vp->v_data);
vp->v_data = NULL;
mutex_exit(&chmp->chm_lock_mountfields);
return (0);
}
@@ -1520,15 +1532,6 @@ chfs_reclaim(void *v)
int
chfs_advlock(void *v)
{
//struct vnode *vp = ((struct vop_advlock_args *) v)->a_vp;
dbg("advlock()\n");
/*
struct chfs_node *node;
node = VP_TO_CHFS_NODE(vp);
return lf_advlock(v, &node->chn_lockf, node->chn_size);
*/
return 0;
}
@@ -1549,35 +1552,26 @@ chfs_strategy(void *v)
int read = (bp->b_flags & B_READ) ? 1 : 0;
int err = 0;
/* dbg("bp dump:\n");
dbg(" ->b_bcount: %d\n", bp->b_bcount);
dbg(" ->b_resid: %d\n", bp->b_resid);
dbg(" ->b_blkno: %llu\n", (unsigned long long)bp->b_blkno);
dbg(" ->b_error: %d\n", bp->b_error);*/
if (read) {
err = chfs_read_data(chmp, vp, bp);
} else {
fd = chfs_alloc_full_dnode();
mutex_enter(&chmp->chm_lock_mountfields);
fd = chfs_alloc_full_dnode();
err = chfs_write_flash_dnode(chmp, vp, bp, fd);
if (err) {
mutex_exit(&chmp->chm_lock_mountfields);
goto out;
}
ip = VTOI(vp);
err = chfs_add_full_dnode_to_inode(chmp, ip, fd);
/*if (err) {
mutex_exit(&chmp->chm_lock_mountfields);
goto out;
}*/
mutex_exit(&chmp->chm_lock_mountfields);
}
out:
biodone(bp);
//dbg("end\n");
return err;
}
+63 -65
View File
@@ -1,4 +1,4 @@
/* $NetBSD: chfs_wbuf.c,v 1.2 2011/11/24 20:50:33 agc Exp $ */
/* $NetBSD: chfs_wbuf.c,v 1.5 2012/10/19 12:44:39 ttoth Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
@@ -35,106 +35,108 @@
#include <dev/flash/flash.h>
#include <sys/uio.h>
#include "chfs.h"
//#include </root/xipffs/netbsd.chfs/chfs.h>
#define DBG_WBUF 1
#define DBG_WBUF 1 /* XXX unused, but should be */
#define PAD(x) (((x)+3)&~3)
#define EB_ADDRESS(x) ( ((unsigned long)(x) / chmp->chm_ebh->eb_size) * chmp->chm_ebh->eb_size )
#define EB_ADDRESS(x) ( rounddown((x), 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) )
#define PAGE_DIV(x) ( rounddown((x), chmp->chm_wbuf_pagesize) )
#define PAGE_MOD(x) ( (x) % (chmp->chm_wbuf_pagesize) )
/* writebuffer options */
enum {
WBUF_NOPAD,
WBUF_SETPAD
};
/*
// 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;
int ret;
size_t retlen;
struct chfs_node_ref *nref;
struct chfs_flash_padding_node* padnode;
KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
KASSERT(mutex_owned(&chmp->chm_lock_sizes));
KASSERT(rw_write_held(&chmp->chm_lock_wbuf));
KASSERT(pad == WBUF_SETPAD || pad == WBUF_NOPAD);
if (pad) {
/* check padding option */
if (pad == WBUF_SETPAD) {
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);
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);
/* add a 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));
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);
/* change sizes after padding node */
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) {
/* write out the buffer */
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);
/* reset the buffer */
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
/*
* chfs_fill_wbuf - write data to wbuf
* 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)
{
/* check available space */
if (len && !chmp->chm_wbuf_len && (len >= chmp->chm_wbuf_pagesize)) {
return 0;
}
/* check buffer's length */
if (len > (chmp->chm_wbuf_pagesize - chmp->chm_wbuf_len)) {
len = chmp->chm_wbuf_pagesize - chmp->chm_wbuf_len;
}
/* write into the wbuf */
memcpy(chmp->chm_wbuf + chmp->chm_wbuf_len, buf, len);
/* update the actual length of writebuffer */
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
@@ -153,19 +155,15 @@ chfs_write_wbuf(struct chfs_mount* chmp, const struct iovec *invecs, long count,
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);
ret = chfs_flush_wbuf(chmp, WBUF_SETPAD);
if (ret)
goto outerr;
}
@@ -173,8 +171,6 @@ chfs_write_wbuf(struct chfs_mount* chmp, const struct iovec *invecs, long count,
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", (unsigned long long)to,
PAD(chmp->chm_wbuf_ofs + chmp->chm_wbuf_len));
@@ -185,10 +181,10 @@ chfs_write_wbuf(struct chfs_mount* chmp, const struct iovec *invecs, long count,
/* 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*/
/* 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);
ret = chfs_flush_wbuf(chmp, WBUF_NOPAD);
if (ret)
goto outerr;
}
@@ -198,41 +194,39 @@ chfs_write_wbuf(struct chfs_mount* chmp, const struct iovec *invecs, long count,
int vlen = invecs[invec].iov_len;
u_char* v = invecs[invec].iov_base;
//dbg("invec:%d len:%d\n", invec, vlen);
/* fill the whole wbuf */
wbuf_retlen = chfs_fill_wbuf(chmp, v, vlen);
if (chmp->chm_wbuf_len == chmp->chm_wbuf_pagesize) {
ret = chfs_flush_wbuf(chmp, NOPAD);
ret = chfs_flush_wbuf(chmp, WBUF_NOPAD);
if (ret) {
goto outerr;
}
}
vlen -= wbuf_retlen;
outvec_to += wbuf_retlen;
v += wbuf_retlen;
donelen += wbuf_retlen;
/* if there is more residual data than the length of the wbuf
* write it out directly until it's fit in the wbuf */
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;
}
/* write the residual data to the wbuf */
wbuf_retlen = chfs_fill_wbuf(chmp, v, vlen);
if (chmp->chm_wbuf_len == chmp->chm_wbuf_pagesize) {
ret = chfs_flush_wbuf(chmp, NOPAD);
ret = chfs_flush_wbuf(chmp, WBUF_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;
}
@@ -245,14 +239,18 @@ outerr:
return ret;
}
/*
* chfs_flush_peding_wbuf - write wbuf to the flash
* Used when we must flush wbuf right now.
* If wbuf has free space, pad it to the size of wbuf and write out.
*/
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);
err = chfs_flush_wbuf(chmp, WBUF_SETPAD);
rw_exit(&chmp->chm_lock_wbuf);
mutex_exit(&chmp->chm_lock_sizes);
return err;
+89 -94
View File
@@ -1,4 +1,4 @@
/* $NetBSD: chfs_write.c,v 1.2 2011/11/24 21:09:37 agc Exp $ */
/* $NetBSD: chfs_write.c,v 1.5 2012/10/19 12:44:39 ttoth Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
@@ -33,18 +33,14 @@
* SUCH DAMAGE.
*/
/*
* chfs_write.c
*
* Created on: 2010.02.17.
* Author: dtengeri
*/
#include <sys/param.h>
#include <sys/buf.h>
#include "chfs.h"
/* chfs_write_flash_vnode - writes out a vnode information to flash */
int
chfs_write_flash_vnode(struct chfs_mount *chmp,
struct chfs_inode *ip, int prio)
@@ -58,6 +54,7 @@ chfs_write_flash_vnode(struct chfs_mount *chmp,
size_t size, retlen;
int err = 0, retries = 0;
/* root vnode is in-memory only */
if (ip->ino == CHFS_ROOTINO)
return 0;
@@ -67,9 +64,8 @@ chfs_write_flash_vnode(struct chfs_mount *chmp,
chvc = ip->chvc;
/* setting up flash_vnode members */
/* setting up flash_vnode's fields */
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));
@@ -86,10 +82,10 @@ chfs_write_flash_vnode(struct chfs_mount *chmp,
fvnode->uid = htole32(ip->uid);
fvnode->node_crc = htole32(crc32(0, (uint8_t *)fvnode, size - 4));
/* write out flash_vnode */
retry:
/* setting up the next eraseblock where we will write */
if (prio == ALLOC_GC) {
/* the GC calls this function */
/* GC called this function */
err = chfs_reserve_space_gc(chmp, CHFS_PAD(size));
if (err)
goto out;
@@ -105,6 +101,7 @@ retry:
goto out;
}
/* allocating a new node reference */
nref = chfs_alloc_node_ref(chmp->chm_nextblock);
if (!nref) {
err = ENOMEM;
@@ -113,12 +110,16 @@ retry:
mutex_enter(&chmp->chm_lock_sizes);
/* caculating offset and 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);
/* write it into the writebuffer */
err = chfs_write_wbuf(chmp, &vec, 1, nref->nref_offset, &retlen);
if (err || retlen != CHFS_PAD(size)) {
/* there was an error during write */
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);
@@ -130,22 +131,28 @@ retry:
goto out;
}
/* try again */
retries++;
mutex_exit(&chmp->chm_lock_sizes);
goto retry;
}
//Everything went well
/* everything went well */
chfs_change_size_used(chmp,
&chmp->chm_blocks[nref->nref_lnr], CHFS_PAD(size));
mutex_exit(&chmp->chm_lock_sizes);
/* add the new nref to vnode cache */
mutex_enter(&chmp->chm_lock_vnocache);
chfs_add_vnode_ref_to_vc(chmp, chvc, nref);
mutex_exit(&chmp->chm_lock_vnocache);
KASSERT(chmp->chm_blocks[nref->nref_lnr].used_size <= chmp->chm_ebh->eb_size);
out:
chfs_free_flash_vnode(fvnode);
return err;
}
/* chfs_write_flash_dirent - writes out a directory entry to flash */
int
chfs_write_flash_dirent(struct chfs_mount *chmp, struct chfs_inode *pdir,
struct chfs_inode *ip, struct chfs_dirent *fd,
@@ -163,6 +170,7 @@ chfs_write_flash_dirent(struct chfs_mount *chmp, struct chfs_inode *pdir,
KASSERT(fd->vno != CHFS_ROOTINO);
/* setting up flash_dirent's fields */
fdirent = chfs_alloc_flash_dirent();
if (!fdirent)
return ENOMEM;
@@ -172,10 +180,7 @@ chfs_write_flash_dirent(struct chfs_mount *chmp, struct chfs_inode *pdir,
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));
@@ -190,12 +195,14 @@ chfs_write_flash_dirent(struct chfs_mount *chmp, struct chfs_inode *pdir,
fdirent->name_crc = crc32(0, (uint8_t *)&(fd->name), fd->nsize);
fdirent->node_crc = crc32(0, (uint8_t *)fdirent, sizeof(*fdirent) - 4);
/* directory's name is written out right after the dirent */
vec[0].iov_base = fdirent;
vec[0].iov_len = sizeof(*fdirent);
vec[1].iov_base = name;
vec[1].iov_len = namelen;
retry:
/* setting up the next eraseblock where we will write */
if (prio == ALLOC_GC) {
/* the GC calls this function */
err = chfs_reserve_space_gc(chmp, CHFS_PAD(size));
@@ -213,6 +220,7 @@ retry:
goto out;
}
/* allocating a new node reference */
nref = chfs_alloc_node_ref(chmp->chm_nextblock);
if (!nref) {
err = ENOMEM;
@@ -224,8 +232,10 @@ retry:
nref->nref_offset = chmp->chm_ebh->eb_size - chmp->chm_nextblock->free_size;
chfs_change_size_free(chmp, chmp->chm_nextblock, -CHFS_PAD(size));
/* write it into the writebuffer */
err = chfs_write_wbuf(chmp, vec, 2, nref->nref_offset, &retlen);
if (err || retlen != CHFS_PAD(size)) {
/* there was an error during write */
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);
@@ -237,33 +247,33 @@ retry:
goto out;
}
/* try again */
retries++;
mutex_exit(&chmp->chm_lock_sizes);
goto retry;
}
// Everything went well
/* 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);
/* add the new nref to the directory chain of vnode cache */
fd->nref = nref;
if (prio != ALLOC_DELETION) {
mutex_enter(&chmp->chm_lock_vnocache);
chfs_add_node_to_list(chmp,
pdir->chvc, nref, &pdir->chvc->dirents);
mutex_exit(&chmp->chm_lock_vnocache);
}
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
*/
/* chfs_write_flash_dnode - writes out a data node to flash */
int
chfs_write_flash_dnode(struct chfs_mount *chmp, struct vnode *vp,
struct buf *bp, struct chfs_full_dnode *fd)
@@ -288,11 +298,6 @@ chfs_write_flash_dnode(struct chfs_mount *chmp, struct vnode *vp,
/* 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;
@@ -312,34 +317,34 @@ chfs_write_flash_dnode(struct chfs_mount *chmp, struct vnode *vp,
dbg("dnode @%llu %ub v%llu\n", (unsigned long long)dnode->offset,
dnode->data_length, (unsigned long long)dnode->version);
/* pad data if needed */
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 */
/* creating iovecs for writebuffer
* data is written out right after the data node */
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;
/* allocating a new node reference */
nref = chfs_alloc_node_ref(chmp->chm_nextblock);
if (!nref) {
err = ENOMEM;
@@ -356,11 +361,10 @@ retry:
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);
/* write it into the writebuffer */
err = chfs_write_wbuf(chmp, vec, 2, nref->nref_offset, &retlen);
if (err || retlen != CHFS_PAD(size)) {
/* there was an error during write */
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);
@@ -372,19 +376,28 @@ retry:
goto out;
}
/* try again */
retries++;
mutex_exit(&chmp->chm_lock_sizes);
goto retry;
}
/* Everything went well */
/* 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);
mutex_enter(&chmp->chm_lock_vnocache);
if (fd->nref != NULL) {
chfs_remove_frags_of_node(chmp, &ip->fragtree, fd->nref);
chfs_remove_and_obsolete(chmp, ip->chvc, fd->nref, &ip->chvc->dnode);
}
/* add the new nref to the data node chain of vnode cache */
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);
mutex_exit(&chmp->chm_lock_vnocache);
out:
chfs_free_flash_dnode(dnode);
if (CHFS_PAD(size) - sizeof(*dnode)) {
@@ -394,27 +407,20 @@ out:
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)
chfs_do_link(struct chfs_inode *ip, struct chfs_inode *parent, const char *name, int namelen, enum chtype 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);
/* setting up the new directory entry */
newfd = chfs_alloc_dirent(namelen + 1);
newfd->vno = ip->ino;
@@ -422,7 +428,6 @@ chfs_do_link(struct chfs_inode *ip, struct chfs_inode *parent, const char *name,
newfd->nsize = namelen;
memcpy(newfd->name, name, namelen);
newfd->name[newfd->nsize] = 0;
// newfd->next = NULL;
ip->chvc->nlink++;
parent->chvc->nlink++;
@@ -431,10 +436,12 @@ chfs_do_link(struct chfs_inode *ip, struct chfs_inode *parent, const char *name,
mutex_enter(&chmp->chm_lock_mountfields);
/* update vnode information */
error = chfs_write_flash_vnode(chmp, ip, ALLOC_NORMAL);
if (error)
return error;
/* write out the new dirent */
error = chfs_write_flash_dirent(chmp,
parent, ip, newfd, ip->ino, ALLOC_NORMAL);
/* TODO: what should we do if error isn't zero? */
@@ -443,28 +450,15 @@ chfs_do_link(struct chfs_inode *ip, struct chfs_inode *parent, const char *name,
/* 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.
* This function set the nlink and vno of the node to zero and
* write its dirent to the media.
*/
int
chfs_do_unlink(struct chfs_inode *ip,
@@ -477,8 +471,6 @@ chfs_do_unlink(struct chfs_inode *ip,
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);
@@ -488,54 +480,57 @@ chfs_do_unlink(struct chfs_inode *ip,
if (fd->vno == ip->ino &&
fd->nsize == namelen &&
!memcmp(fd->name, name, fd->nsize)) {
if (fd->type == VDIR && ip->chvc->nlink == 2)
/* remove every fragment of the file */
chfs_kill_fragtree(chmp, &ip->fragtree);
/* decrease number of links to the file */
if (fd->type == CHT_DIR && ip->chvc->nlink == 2)
ip->chvc->nlink = 0;
else
ip->chvc->nlink--;
fd->type = VNON;
fd->type = CHT_BLANK;
/* remove from parent's directory entries */
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;
}
mutex_enter(&chmp->chm_lock_vnocache);
//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);
dbg("FD->NREF vno: %llu, lnr: %u, ofs: %u\n",
fd->vno, fd->nref->nref_lnr, fd->nref->nref_offset);
chfs_remove_and_obsolete(chmp, parent->chvc, fd->nref,
&parent->chvc->dirents);
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);
dbg("FD->NREF vno: %llu, lnr: %u, ofs: %u\n",
fd->vno, fd->nref->nref_lnr, fd->nref->nref_offset);
/* set nref_next field */
chfs_add_node_to_list(chmp, parent->chvc, fd->nref,
&parent->chvc->dirents);
/* remove from the list */
chfs_remove_and_obsolete(chmp, parent->chvc, fd->nref,
&parent->chvc->dirents);
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;
/* clean dnode list */
while (ip->chvc->dnode != (struct chfs_node_ref *)ip->chvc) {
nref = ip->chvc->dnode;
chfs_remove_frags_of_node(chmp, &ip->fragtree, nref);
chfs_remove_and_obsolete(chmp, ip->chvc, nref, &ip->chvc->dnode);
}
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;
/* clean vnode information (list) */
while (ip->chvc->v != (struct chfs_node_ref *)ip->chvc) {
nref = ip->chvc->v;
chfs_remove_and_obsolete(chmp, ip->chvc, nref, &ip->chvc->v);
}
ip->chvc->v = ip->chvc->v->nref_next;
/* decrease number of links to parent */
parent->chvc->nlink--;
mutex_exit(&chmp->chm_lock_vnocache);
//TODO: if error
}
}
-48
View File
@@ -1,48 +0,0 @@
/* $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>
+1 -14
View File
@@ -1,4 +1,4 @@
/* $NetBSD: debug.h,v 1.1 2011/11/24 15:51:32 ahoka Exp $ */
/* $NetBSD: debug.h,v 1.2 2012/04/12 15:31:01 ttoth Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
@@ -30,19 +30,6 @@
* 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__
+2 -4
View File
@@ -1,4 +1,4 @@
/* $NetBSD: ebh.c,v 1.2 2011/11/25 11:15:24 ahoka Exp $ */
/* $NetBSD: ebh.c,v 1.3 2012/08/10 09:26:58 ttoth Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
@@ -1730,6 +1730,7 @@ ebh_read_leb(struct chfs_ebh *ebh, int lnr, char *buf, uint32_t offset,
err = leb_read_lock(ebh, lnr);
if (err)
return err;
pebnr = ebh->lmap[lnr];
/* If PEB is not mapped the buffer is filled with 0xFF */
if (EBH_LEB_UNMAPPED == pebnr) {
@@ -1747,9 +1748,6 @@ ebh_read_leb(struct chfs_ebh *ebh, int lnr, char *buf, uint32_t offset,
KASSERT(len == *retlen);
leb_read_unlock(ebh, lnr);
return err;
out_free:
leb_read_unlock(ebh, lnr);
return err;
+23 -25
View File
@@ -1,4 +1,4 @@
/* $NetBSD: ebh.h,v 1.1 2011/11/24 15:51:32 ahoka Exp $ */
/* $NetBSD: ebh.h,v 1.3 2012/10/19 12:44:39 ttoth Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
@@ -32,16 +32,10 @@
* SUCH DAMAGE.
*/
/*
* ebh.h
*
* Created on: 2009.11.03.
* Author: dtengeri
*/
#ifndef EBH_H_
#define EBH_H_
#ifdef _KERNEL
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/cdefs.h>
@@ -57,10 +51,27 @@
#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>
#include "debug.h"
#include "ebh_misc.h"
#endif /* _KERNEL */
#include "ebh_media.h"
/**
* 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;
};
#ifdef _KERNEL
/* Maximum retries when getting new PEB before exit with failure */
#define CHFS_MAX_GET_PEB_RETRIES 2
@@ -134,7 +145,6 @@ 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
@@ -181,19 +191,6 @@ 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
@@ -314,5 +311,6 @@ 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 /* _KERNEL */
#endif /* EBH_H_ */
+4 -12
View File
@@ -1,4 +1,4 @@
/* $NetBSD: ebh_misc.h,v 1.1 2011/11/24 15:51:32 ahoka Exp $ */
/* $NetBSD: ebh_misc.h,v 1.2 2012/10/19 12:44:39 ttoth Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
@@ -33,20 +33,15 @@
#ifndef EBH_MISC_H_
#define EBH_MISC_H_
/******************************************************************************/
/* EBH specific functions */
/******************************************************************************/
/* 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) \
{ \
@@ -70,11 +65,8 @@
} \
}
/**
/*
* 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) \
{ \
+65 -122
View File
@@ -40,23 +40,20 @@
typedef uint16_t le16;
typedef uint32_t le32;
typedef uint64_t le64;
#endif
/*****************************************************************************/
/* File system specific structures */
/*****************************************************************************/
#endif /* _LE_TYPES */
/* node types */
enum {
CHFS_NODETYPE_VNODE = 1,
CHFS_NODETYPE_DATA,
CHFS_NODETYPE_DIRENT,
CHFS_NODETYPE_PADDING,
CHFS_NODETYPE_VNODE = 1, /* vnode information */
CHFS_NODETYPE_DATA, /* data node */
CHFS_NODETYPE_DIRENT, /* directory enrty */
CHFS_NODETYPE_PADDING, /* padding node */
};
//#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.
/*
* 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
@@ -64,137 +61,83 @@ enum {
/* 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 -
* node header, its members are same for all nodes, used at scan
*/
struct chfs_flash_node_hdr
{
le16 magic;
le16 type;
le32 length;
le32 hdr_crc;
le16 magic; /* filesystem magic */
le16 type; /* node type */
le32 length; /* length of node */
le32 hdr_crc; /* crc of the first 3 fields */
} __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 - vnode informations stored on flash */
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*/
le16 magic; /* filesystem magic */
le16 type; /* node type (should be CHFS_NODETYPE_VNODE) */
le32 length; /* length of node */
le32 hdr_crc; /* crc of the first 3 fields */
le64 vno; /* vnode number */
le64 version; /* version of node */
le32 uid; /* owner of file */
le32 gid; /* group of file */
le32 mode; /* permission of vnode */
le32 dn_size; /* size of written data */
le32 atime; /* last access time */
le32 mtime; /* last modification time */
le32 ctime; /* change time */
le32 dsize; /* NOT USED, backward compatibility */
le32 node_crc; /* crc of all the previous fields */
} __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 - data stored on flash */
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];
le16 magic; /* filesystem magic */
le16 type; /* node type (should be CHFS_NODETYPE_DATA) */
le32 length; /* length of vnode with data */
le32 hdr_crc; /* crc of the first 3 fields */
le64 vno; /* vnode number */
le64 version; /* version of node */
le64 offset; /* offset in the file */
le32 data_length; /* length of data */
le32 data_crc; /* crc of data*/
le32 node_crc; /* crc of full node */
uint8_t data[0]; /* data */
} __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 -
* directory entry information stored on flash
*/
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];
le16 magic; /* filesystem magic */
le16 type; /* node type (should be CHFS_NODETYPE_DIRENT) */
le32 length; /* length of node with name */
le32 hdr_crc; /* crc of the first 3 fields */
le64 vno; /* vnode number */
le64 pvno; /* parent's vnode number */
le64 version; /* version of node */
le32 mctime; /* */
uint8_t nsize; /* length of name */
uint8_t dtype; /* file type */
uint8_t unused[2]; /* just for padding */
le32 name_crc; /* crc of name */
le32 node_crc; /* crc of full node */
uint8_t name[0]; /* name of directory entry */
} __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 - spaceholder node on flash */
struct chfs_flash_padding_node
{
le16 magic;
le16 type;
le32 length;
le32 hdr_crc;
le16 magic; /* filesystem magic */
le16 type; /* node type (should be CHFS_NODETYPE_PADDING )*/
le32 length; /* length of node */
le32 hdr_crc; /* crc of the first 3 fields */
} __packed;
#endif /* __CHFS_MEDIA_H__ */
+53 -10
View File
@@ -1,4 +1,4 @@
/* $NetBSD: ext2fs.h,v 1.29 2009/11/27 11:16:54 tsutsui Exp $ */
/* $NetBSD: ext2fs.h,v 1.36 2013/06/23 07:28:37 dholland Exp $ */
/*
* Copyright (c) 1982, 1986, 1993
@@ -198,15 +198,57 @@ struct m_ext2fs {
/* compatible/incompatible features */
#define EXT2F_COMPAT_PREALLOC 0x0001
#define EXT2F_COMPAT_AFS 0x0002
#define EXT2F_COMPAT_HASJOURNAL 0x0004
#define EXT2F_COMPAT_EXTATTR 0x0008
#define EXT2F_COMPAT_RESIZE 0x0010
#define EXT2F_COMPAT_DIRHASHINDEX 0x0020
#define EXT2F_COMPAT_BITS \
"\20" \
"\06COMPAT_DIRHASHINDEX" \
"\05COMPAT_RESIZE" \
"\04COMPAT_EXTATTR" \
"\03COMPAT_HASJOURNAL" \
"\02COMPAT_AFS" \
"\01COMPAT_PREALLOC"
#define EXT2F_ROCOMPAT_SPARSESUPER 0x0001
#define EXT2F_ROCOMPAT_LARGEFILE 0x0002
#define EXT2F_ROCOMPAT_BTREE_DIR 0x0004
#define EXT2F_ROCOMPAT_HUGE_FILE 0x0008
#define EXT2F_ROCOMPAT_GDT_CSUM 0x0010
#define EXT2F_ROCOMPAT_DIR_NLINK 0x0020
#define EXT2F_ROCOMPAT_EXTRA_ISIZE 0x0040
#define EXT2F_ROCOMPAT_BITS \
"\20" \
"\07ROCOMPAT_EXTRA_ISIZE" \
"\06ROCOMPAT_DIR_NLINK" \
"\05ROCOMPAT_GDT_CSUM" \
"\04ROCOMPAT_HUGE_FILE" \
"\03ROCOMPAT_BTREE_DIR" \
"\02ROCOMPAT_LARGEFILE" \
"\01ROCOMPAT_SPARSESUPER"
#define EXT2F_INCOMPAT_COMP 0x0001
#define EXT2F_INCOMPAT_FTYPE 0x0002
#define EXT2F_INCOMPAT_REPLAY_JOURNAL 0x0004
#define EXT2F_INCOMPAT_USES_JOURNAL 0x0008
#define EXT2F_INCOMPAT_META_BG 0x0010
#define EXT2F_INCOMPAT_EXTENTS 0x0040
#define EXT2F_INCOMPAT_64BIT 0x0080
#define EXT2F_INCOMPAT_MMP 0x0100
#define EXT2F_INCOMPAT_FLEX_BG 0x0200
#define EXT2F_INCOMPAT_BITS \
"\20" \
"\012INCOMPAT_FLEX_BG" \
"\011INCOMPAT_MMP" \
"\010INCOMPAT_64BIT" \
"\07INCOMPAT_EXTENTS" \
"\05INCOMPAT_META_BG" \
"\04INCOMPAT_USES_JOURNAL" \
"\03INCOMPAT_REPLAY_JOURNAL" \
"\02INCOMPAT_FTYPE" \
"\01INCOMPAT_COMP"
/*
* Features supported in this implementation
@@ -223,7 +265,8 @@ struct m_ext2fs {
*/
#define EXT2F_COMPAT_SUPP 0x0000
#define EXT2F_ROCOMPAT_SUPP (EXT2F_ROCOMPAT_SPARSESUPER \
| EXT2F_ROCOMPAT_LARGEFILE)
| EXT2F_ROCOMPAT_LARGEFILE \
| EXT2F_ROCOMPAT_HUGE_FILE)
#define EXT2F_INCOMPAT_SUPP EXT2F_INCOMPAT_FTYPE
/*
@@ -319,8 +362,8 @@ void e2fs_cg_bswap(struct ext2_gd *, struct ext2_gd *, int);
* Turn file system block numbers into disk block addresses.
* This maps file system blocks to device size blocks.
*/
#define fsbtodb(fs, b) ((b) << (fs)->e2fs_fsbtodb)
#define dbtofsb(fs, b) ((b) >> (fs)->e2fs_fsbtodb)
#define EXT2_FSBTODB(fs, b) ((b) << (fs)->e2fs_fsbtodb)
#define EXT2_DBTOFSB(fs, b) ((b) >> (fs)->e2fs_fsbtodb)
/*
* Macros for handling inode numbers:
@@ -347,15 +390,15 @@ void e2fs_cg_bswap(struct ext2_gd *, struct ext2_gd *, int);
* quantities by using shifts and masks in place of divisions
* modulos and multiplications.
*/
#define blkoff(fs, loc) /* calculates (loc % fs->e2fs_bsize) */ \
#define ext2_blkoff(fs, loc) /* calculates (loc % fs->e2fs_bsize) */ \
((loc) & (fs)->e2fs_qbmask)
#define lblktosize(fs, blk) /* calculates (blk * fs->e2fs_bsize) */ \
#define ext2_lblktosize(fs, blk) /* calculates (blk * fs->e2fs_bsize) */ \
((blk) << (fs)->e2fs_bshift)
#define lblkno(fs, loc) /* calculates (loc / fs->e2fs_bsize) */ \
#define ext2_lblkno(fs, loc) /* calculates (loc / fs->e2fs_bsize) */ \
((loc) >> (fs)->e2fs_bshift)
#define blkroundup(fs, size) /* calculates roundup(size, fs->e2fs_bsize) */ \
#define ext2_blkroundup(fs, size) /* calculates roundup(size, fs->e2fs_bsize) */ \
(((size) + (fs)->e2fs_qbmask) & (fs)->e2fs_bmask)
#define fragroundup(fs, size) /* calculates roundup(size, fs->e2fs_bsize) */ \
#define ext2_fragroundup(fs, size) /* calculates roundup(size, fs->e2fs_bsize) */ \
(((size) + (fs)->e2fs_qbmask) & (fs)->e2fs_bmask)
/*
* Determine the number of available frags given a
@@ -367,6 +410,6 @@ void e2fs_cg_bswap(struct ext2_gd *, struct ext2_gd *, int);
/*
* Number of indirects in a file system block.
*/
#define NINDIR(fs) ((fs)->e2fs_bsize / sizeof(uint32_t))
#define EXT2_NINDIR(fs) ((fs)->e2fs_bsize / sizeof(uint32_t))
#endif /* !_UFS_EXT2FS_EXT2FS_H_ */
+7 -11
View File
@@ -1,4 +1,4 @@
/* $NetBSD: ext2fs_alloc.c,v 1.42 2011/03/06 04:46:26 rmind Exp $ */
/* $NetBSD: ext2fs_alloc.c,v 1.45 2013/06/23 02:06:05 dholland Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@@ -60,7 +60,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ext2fs_alloc.c,v 1.42 2011/03/06 04:46:26 rmind Exp $");
__KERNEL_RCSID(0, "$NetBSD: ext2fs_alloc.c,v 1.45 2013/06/23 02:06:05 dholland Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -135,7 +135,7 @@ ext2fs_alloc(struct inode *ip, daddr_t lbn, daddr_t bpref,
bno = (daddr_t)ext2fs_hashalloc(ip, cg, bpref, fs->e2fs_bsize,
ext2fs_alloccg);
if (bno > 0) {
ip->i_e2fs_nblock += btodb(fs->e2fs_bsize);
ext2fs_setnblock(ip, ext2fs_nblock(ip) + btodb(fs->e2fs_bsize));
ip->i_flag |= IN_CHANGE | IN_UPDATE;
*bnp = bno;
return (0);
@@ -355,11 +355,10 @@ ext2fs_alloccg(struct inode *ip, int cg, daddr_t bpref, int size)
fs = ip->i_e2fs;
if (fs->e2fs_gd[cg].ext2bgd_nbfree == 0)
return (0);
error = bread(ip->i_devvp, fsbtodb(fs,
error = bread(ip->i_devvp, EXT2_FSBTODB(fs,
fs->e2fs_gd[cg].ext2bgd_b_bitmap),
(int)fs->e2fs_bsize, NOCRED, B_MODIFY, &bp);
if (error) {
brelse(bp, 0);
return (0);
}
bbp = (char *)bp->b_data;
@@ -442,11 +441,10 @@ ext2fs_nodealloccg(struct inode *ip, int cg, daddr_t ipref, int mode)
fs = ip->i_e2fs;
if (fs->e2fs_gd[cg].ext2bgd_nifree == 0)
return (0);
error = bread(ip->i_devvp, fsbtodb(fs,
error = bread(ip->i_devvp, EXT2_FSBTODB(fs,
fs->e2fs_gd[cg].ext2bgd_i_bitmap),
(int)fs->e2fs_bsize, NOCRED, B_MODIFY, &bp);
if (error) {
brelse(bp, 0);
return (0);
}
ibp = (char *)bp->b_data;
@@ -511,10 +509,9 @@ ext2fs_blkfree(struct inode *ip, daddr_t bno)
return;
}
error = bread(ip->i_devvp,
fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_b_bitmap),
EXT2_FSBTODB(fs, fs->e2fs_gd[cg].ext2bgd_b_bitmap),
(int)fs->e2fs_bsize, NOCRED, B_MODIFY, &bp);
if (error) {
brelse(bp, 0);
return;
}
bbp = (char *)bp->b_data;
@@ -555,10 +552,9 @@ ext2fs_vfree(struct vnode *pvp, ino_t ino, int mode)
fs->e2fs_fsmnt);
cg = ino_to_cg(fs, ino);
error = bread(pip->i_devvp,
fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_i_bitmap),
EXT2_FSBTODB(fs, fs->e2fs_gd[cg].ext2bgd_i_bitmap),
(int)fs->e2fs_bsize, NOCRED, B_MODIFY, &bp);
if (error) {
brelse(bp, 0);
return (0);
}
ibp = (char *)bp->b_data;
+15 -19
View File
@@ -1,4 +1,4 @@
/* $NetBSD: ext2fs_balloc.c,v 1.34 2009/10/19 18:41:17 bouyer Exp $ */
/* $NetBSD: ext2fs_balloc.c,v 1.39 2013/06/23 07:28:37 dholland Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@@ -60,7 +60,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ext2fs_balloc.c,v 1.34 2009/10/19 18:41:17 bouyer Exp $");
__KERNEL_RCSID(0, "$NetBSD: ext2fs_balloc.c,v 1.39 2013/06/23 07:28:37 dholland Exp $");
#if defined(_KERNEL_OPT)
#include "opt_uvmhist.h"
@@ -96,12 +96,12 @@ ext2fs_balloc(struct inode *ip, daddr_t bn, int size,
daddr_t nb;
struct buf *bp, *nbp;
struct vnode *vp = ITOV(ip);
struct indir indirs[NIADDR + 2];
struct indir indirs[EXT2FS_NIADDR + 2];
daddr_t newb, lbn, pref;
int32_t *bap; /* XXX ondisk32 */
int num, i, error;
u_int deallocated;
daddr_t *blkp, *allocblk, allociblk[NIADDR + 1];
daddr_t *blkp, *allocblk, allociblk[EXT2FS_NIADDR + 1];
int32_t *allocib; /* XXX ondisk32 */
int unwindidx = -1;
UVMHIST_FUNC("ext2fs_balloc"); UVMHIST_CALLED(ubchist);
@@ -117,9 +117,9 @@ ext2fs_balloc(struct inode *ip, daddr_t bn, int size,
lbn = bn;
/*
* The first NDADDR blocks are direct blocks
* The first EXT2FS_NDADDR blocks are direct blocks
*/
if (bn < NDADDR) {
if (bn < EXT2FS_NDADDR) {
/* XXX ondisk32 */
nb = fs2h32(ip->i_e2fs_blocks[bn]);
if (nb != 0) {
@@ -132,7 +132,6 @@ ext2fs_balloc(struct inode *ip, daddr_t bn, int size,
error = bread(vp, bn, fs->e2fs_bsize, NOCRED,
B_MODIFY, &bp);
if (error) {
brelse(bp, 0);
return (error);
}
*bpp = bp;
@@ -156,7 +155,7 @@ ext2fs_balloc(struct inode *ip, daddr_t bn, int size,
ip->i_flag |= IN_CHANGE | IN_UPDATE;
if (bpp != NULL) {
bp = getblk(vp, bn, fs->e2fs_bsize, 0, 0);
bp->b_blkno = fsbtodb(fs, newb);
bp->b_blkno = EXT2_FSBTODB(fs, newb);
if (flags & B_CLRBUF)
clrbuf(bp);
*bpp = bp;
@@ -178,7 +177,7 @@ ext2fs_balloc(struct inode *ip, daddr_t bn, int size,
*/
--num;
/* XXX ondisk32 */
nb = fs2h32(ip->i_e2fs_blocks[NDADDR + indirs[0].in_off]);
nb = fs2h32(ip->i_e2fs_blocks[EXT2FS_NDADDR + indirs[0].in_off]);
allocib = NULL;
allocblk = allociblk;
if (nb == 0) {
@@ -190,7 +189,7 @@ ext2fs_balloc(struct inode *ip, daddr_t bn, int size,
*allocblk++ = nb;
ip->i_e2fs_last_blk = newb;
bp = getblk(vp, indirs[1].in_lbn, fs->e2fs_bsize, 0, 0);
bp->b_blkno = fsbtodb(fs, newb);
bp->b_blkno = EXT2_FSBTODB(fs, newb);
clrbuf(bp);
/*
* Write synchronously so that indirect blocks
@@ -199,7 +198,7 @@ ext2fs_balloc(struct inode *ip, daddr_t bn, int size,
if ((error = bwrite(bp)) != 0)
goto fail;
unwindidx = 0;
allocib = &ip->i_e2fs_blocks[NDADDR + indirs[0].in_off];
allocib = &ip->i_e2fs_blocks[EXT2FS_NDADDR + indirs[0].in_off];
/* XXX ondisk32 */
*allocib = h2fs32((int32_t)newb);
ip->i_flag |= IN_CHANGE | IN_UPDATE;
@@ -211,7 +210,6 @@ ext2fs_balloc(struct inode *ip, daddr_t bn, int size,
error = bread(vp,
indirs[i].in_lbn, (int)fs->e2fs_bsize, NOCRED, 0, &bp);
if (error) {
brelse(bp, 0);
goto fail;
}
bap = (int32_t *)bp->b_data; /* XXX ondisk32 */
@@ -233,7 +231,7 @@ ext2fs_balloc(struct inode *ip, daddr_t bn, int size,
*allocblk++ = nb;
ip->i_e2fs_last_blk = newb;
nbp = getblk(vp, indirs[i].in_lbn, fs->e2fs_bsize, 0, 0);
nbp->b_blkno = fsbtodb(fs, nb);
nbp->b_blkno = EXT2_FSBTODB(fs, nb);
clrbuf(nbp);
/*
* Write synchronously so that indirect blocks
@@ -284,7 +282,7 @@ ext2fs_balloc(struct inode *ip, daddr_t bn, int size,
}
if (bpp != NULL) {
nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0);
nbp->b_blkno = fsbtodb(fs, nb);
nbp->b_blkno = EXT2_FSBTODB(fs, nb);
if (flags & B_CLRBUF)
clrbuf(nbp);
*bpp = nbp;
@@ -297,12 +295,11 @@ ext2fs_balloc(struct inode *ip, daddr_t bn, int size,
error = bread(vp, lbn, (int)fs->e2fs_bsize, NOCRED,
B_MODIFY, &nbp);
if (error) {
brelse(nbp, 0);
goto fail;
}
} else {
nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0);
nbp->b_blkno = fsbtodb(fs, nb);
nbp->b_blkno = EXT2_FSBTODB(fs, nb);
}
*bpp = nbp;
}
@@ -326,7 +323,6 @@ fail:
(int)fs->e2fs_bsize, NOCRED, B_MODIFY, &bp);
if (r) {
panic("Could not unwind indirect block, error %d", r);
brelse(bp, 0);
} else {
bap = (int32_t *)bp->b_data; /* XXX ondisk32 */
bap[indirs[unwindidx].in_off] = 0;
@@ -343,7 +339,7 @@ fail:
}
}
if (deallocated) {
ip->i_e2fs_nblock -= btodb(deallocated);
ext2fs_setnblock(ip, ext2fs_nblock(ip) - btodb(deallocated));
ip->i_e2fs_flags |= IN_CHANGE | IN_UPDATE;
}
return error;
@@ -370,7 +366,7 @@ ext2fs_gop_alloc(struct vnode *vp, off_t off, off_t len, int flags,
UVMHIST_LOG(ubchist, "off 0x%x len 0x%x bsize 0x%x",
off, len, bsize, 0);
error = ext2fs_balloc(ip, lblkno(fs, off), bsize, cred,
error = ext2fs_balloc(ip, ext2_lblkno(fs, off), bsize, cred,
NULL, flags);
if (error) {
UVMHIST_LOG(ubchist, "error %d", error, 0,0,0);
+7 -7
View File
@@ -1,4 +1,4 @@
/* $NetBSD: ext2fs_bmap.c,v 1.25 2009/10/19 18:41:17 bouyer Exp $ */
/* $NetBSD: ext2fs_bmap.c,v 1.26 2013/01/22 09:39:15 dholland Exp $ */
/*
* Copyright (c) 1989, 1991, 1993
@@ -65,7 +65,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ext2fs_bmap.c,v 1.25 2009/10/19 18:41:17 bouyer Exp $");
__KERNEL_RCSID(0, "$NetBSD: ext2fs_bmap.c,v 1.26 2013/01/22 09:39:15 dholland Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -139,7 +139,7 @@ ext2fs_bmaparray(struct vnode *vp, daddr_t bn, daddr_t *bnp, struct indir *ap,
struct buf *bp, *cbp;
struct ufsmount *ump;
struct mount *mp;
struct indir a[NIADDR+1], *xap;
struct indir a[EXT2FS_NIADDR+1], *xap;
daddr_t daddr;
daddr_t metalbn;
int error, maxrun = 0, num;
@@ -163,14 +163,14 @@ ext2fs_bmaparray(struct vnode *vp, daddr_t bn, daddr_t *bnp, struct indir *ap,
maxrun = MAXBSIZE / mp->mnt_stat.f_iosize - 1;
}
if (bn >= 0 && bn < NDADDR) {
if (bn >= 0 && bn < EXT2FS_NDADDR) {
/* XXX ondisk32 */
*bnp = blkptrtodb(ump, fs2h32(ip->i_e2fs_blocks[bn]));
if (*bnp == 0)
*bnp = -1;
else if (runp)
/* XXX ondisk32 */
for (++bn; bn < NDADDR && *runp < maxrun &&
for (++bn; bn < EXT2FS_NDADDR && *runp < maxrun &&
is_sequential(ump, (daddr_t)fs2h32(ip->i_e2fs_blocks[bn - 1]),
(daddr_t)fs2h32(ip->i_e2fs_blocks[bn]));
++bn, ++*runp);
@@ -187,10 +187,10 @@ ext2fs_bmaparray(struct vnode *vp, daddr_t bn, daddr_t *bnp, struct indir *ap,
/* Get disk address out of indirect block array */
/* XXX ondisk32 */
daddr = fs2h32(ip->i_e2fs_blocks[NDADDR + xap->in_off]);
daddr = fs2h32(ip->i_e2fs_blocks[EXT2FS_NDADDR + xap->in_off]);
#ifdef DIAGNOSTIC
if (num > NIADDR + 1 || num < 1) {
if (num > EXT2FS_NIADDR + 1 || num < 1) {
printf("ext2fs_bmaparray: num=%d\n", num);
panic("ext2fs_bmaparray: num");
}
+7 -4
View File
@@ -1,4 +1,4 @@
/* $NetBSD: ext2fs_bswap.c,v 1.16 2009/10/19 18:41:17 bouyer Exp $ */
/* $NetBSD: ext2fs_bswap.c,v 1.19 2013/01/22 09:39:15 dholland Exp $ */
/*
* Copyright (c) 1997 Manuel Bouyer.
@@ -26,7 +26,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ext2fs_bswap.c,v 1.16 2009/10/19 18:41:17 bouyer Exp $");
__KERNEL_RCSID(0, "$NetBSD: ext2fs_bswap.c,v 1.19 2013/01/22 09:39:15 dholland Exp $");
#include <sys/types.h>
#include <ufs/ext2fs/ext2fs.h>
@@ -38,7 +38,7 @@ __KERNEL_RCSID(0, "$NetBSD: ext2fs_bswap.c,v 1.16 2009/10/19 18:41:17 bouyer Exp
#include <string.h>
#endif
/* These functions are only needed if native byte order is not big endian */
/* These functions are only needed if native byte order is not little endian */
#if BYTE_ORDER == BIG_ENDIAN
void
e2fs_sb_bswap(struct ext2fs *old, struct ext2fs *new)
@@ -109,13 +109,16 @@ void e2fs_i_bswap(struct ext2fs_dinode *old, struct ext2fs_dinode *new)
new->e2di_dtime = bswap32(old->e2di_dtime);
new->e2di_nblock = bswap32(old->e2di_nblock);
new->e2di_flags = bswap32(old->e2di_flags);
new->e2di_version = bswap32(old->e2di_version);
new->e2di_gen = bswap32(old->e2di_gen);
new->e2di_facl = bswap32(old->e2di_facl);
new->e2di_dacl = bswap32(old->e2di_dacl);
new->e2di_faddr = bswap32(old->e2di_faddr);
new->e2di_nblock_high = bswap16(old->e2di_nblock_high);
new->e2di_facl_high = bswap16(old->e2di_facl_high);
new->e2di_uid_high = bswap16(old->e2di_uid_high);
new->e2di_gid_high = bswap16(old->e2di_gid_high);
memcpy(&new->e2di_blocks[0], &old->e2di_blocks[0],
(NDADDR + NIADDR) * sizeof(uint32_t));
(EXT2FS_NDADDR + EXT2FS_NIADDR) * sizeof(uint32_t));
}
#endif
+37 -22
View File
@@ -1,4 +1,4 @@
/* $NetBSD: ext2fs_dinode.h,v 1.22 2009/11/27 11:16:54 tsutsui Exp $ */
/* $NetBSD: ext2fs_dinode.h,v 1.26 2013/01/22 09:39:15 dholland Exp $ */
/*
* Copyright (c) 1982, 1989, 1993
@@ -92,40 +92,45 @@
* are defined by types with precise widths.
*/
#define NDADDR 12 /* Direct addresses in inode. */
#define NIADDR 3 /* Indirect addresses in inode. */
/*
* XXX these are the same values as UFS_NDADDR/UFS_NIADDR and it is
* far from clear that there isn't code that relies on them being the
* same.
*/
#define EXT2FS_NDADDR 12 /* Direct addresses in inode. */
#define EXT2FS_NIADDR 3 /* Indirect addresses in inode. */
#define EXT2_MAXSYMLINKLEN ((NDADDR+NIADDR) * sizeof (uint32_t))
#define EXT2_MAXSYMLINKLEN ((EXT2FS_NDADDR+EXT2FS_NIADDR) * sizeof (uint32_t))
struct ext2fs_dinode {
uint16_t e2di_mode; /* 0: IFMT, permissions; see below. */
uint16_t e2di_uid; /* 2: Owner UID */
uint32_t e2di_size; /* 4: Size (in bytes) */
uint32_t e2di_atime; /* 8: Acces time */
uint32_t e2di_ctime; /* 12: Create time */
uint32_t e2di_mtime; /* 16: Modification time */
uint32_t e2di_dtime; /* 20: Deletion time */
uint32_t e2di_size; /* 4: Size (in bytes) */
uint32_t e2di_atime; /* 8: Access time */
uint32_t e2di_ctime; /* 12: Create time */
uint32_t e2di_mtime; /* 16: Modification time */
uint32_t e2di_dtime; /* 20: Deletion time */
uint16_t e2di_gid; /* 24: Owner GID */
uint16_t e2di_nlink; /* 26: File link count */
uint32_t e2di_nblock; /* 28: Blocks count */
uint32_t e2di_flags; /* 32: Status flags (chflags) */
uint32_t e2di_linux_reserved1; /* 36 */
uint32_t e2di_blocks[NDADDR+NIADDR]; /* 40: disk blocks */
uint32_t e2di_version; /* 36: was reserved1 */
uint32_t e2di_blocks[EXT2FS_NDADDR+EXT2FS_NIADDR];
/* 40: disk blocks */
uint32_t e2di_gen; /* 100: generation number */
uint32_t e2di_facl; /* 104: file ACL (not implemented) */
uint32_t e2di_dacl; /* 108: dir ACL (not implemented) */
uint32_t e2di_faddr; /* 112: fragment address */
uint8_t e2di_nfrag; /* 116: fragment number */
uint8_t e2di_fsize; /* 117: fragment size */
uint16_t e2di_linux_reserved2; /* 118 */
uint16_t e2di_nblock_high; /* 116: Blocks count bits 47:32 */
uint16_t e2di_facl_high; /* 118: file ACL bits 47:32 */
uint16_t e2di_uid_high; /* 120: Owner UID top 16 bits */
uint16_t e2di_gid_high; /* 122: Owner GID top 16 bits */
uint32_t e2di_linux_reserved3; /* 124 */
};
#define E2MAXSYMLINKLEN ((NDADDR + NIADDR) * sizeof(uint32_t))
/* XXX how does this differ from EXT2_MAXSYMLINKLEN above? */
#define E2MAXSYMLINKLEN ((EXT2FS_NDADDR + EXT2FS_NIADDR) * sizeof(uint32_t))
/* File permissions. */
#define EXT2_IEXEC 0000100 /* Executable. */
@@ -146,13 +151,23 @@ struct ext2fs_dinode {
#define EXT2_IFSOCK 0140000 /* UNIX domain socket. */
/* file flags */
#define EXT2_SECRM 0x00000001 /* Secure deletion */
#define EXT2_UNRM 0x00000002 /* Undelete */
#define EXT2_COMPR 0x00000004 /* Compress file */
#define EXT2_SYNC 0x00000008 /* Synchronous updates */
#define EXT2_IMMUTABLE 0x00000010 /* Immutable file */
#define EXT2_SECRM 0x00000001 /* Secure deletion */
#define EXT2_UNRM 0x00000002 /* Undelete */
#define EXT2_COMPR 0x00000004 /* Compress file */
#define EXT2_SYNC 0x00000008 /* Synchronous updates */
#define EXT2_IMMUTABLE 0x00000010 /* Immutable file */
#define EXT2_APPEND 0x00000020 /* writes to file may only append */
#define EXT2_NODUMP 0x00000040 /* do not dump file */
#define EXT2_NODUMP 0x00000040 /* do not dump file */
#define EXT2_NOATIME 0x00000080 /* do not update atime */
#define EXT2_INDEX 0x00001000 /* hash-indexed directory */
#define EXT2_IMAGIC 0x00002000 /* AFS directory */
#define EXT2_JOURNAL_DATA 0x00004000 /* file data should be journaled */
#define EXT2_NOTAIL 0x00008000 /* file tail should not be merged */
#define EXT2_DIRSYNC 0x00010000 /* dirsync behaviour */
#define EXT2_TOPDIR 0x00020000 /* Top of directory hierarchies*/
#define EXT2_HUGE_FILE 0x00040000 /* Set to each huge file */
#define EXT2_EXTENTS 0x00080000 /* Inode uses extents */
#define EXT2_EOFBLOCKS 0x00400000 /* Blocks allocated beyond EOF */
/* Size of on-disk inode. */
#define EXT2_REV0_DINODE_SIZE sizeof(struct ext2fs_dinode)
+3 -1
View File
@@ -1,4 +1,4 @@
/* $NetBSD: ext2fs_dir.h,v 1.18 2009/10/19 18:41:17 bouyer Exp $ */
/* $NetBSD: ext2fs_dir.h,v 1.19 2012/05/09 00:21:18 riastradh Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@@ -67,6 +67,8 @@
#ifndef _UFS_EXT2FS_EXT2FS_DIR_H_
#define _UFS_EXT2FS_EXT2FS_DIR_H_
#include <ufs/ext2fs/ext2fs_dinode.h>
/*
* Theoretically, directories can be more than 2Gb in length, however, in
* practice this seems unlikely. So, we define the type doff_t as a 32-bit
+6 -3
View File
@@ -1,4 +1,4 @@
/* $NetBSD: ext2fs_extern.h,v 1.43 2011/07/12 16:59:48 dholland Exp $ */
/* $NetBSD: ext2fs_extern.h,v 1.46 2012/11/21 23:11:23 jakllsch Exp $ */
/*-
* Copyright (c) 1991, 1993, 1994
@@ -77,6 +77,7 @@ struct uio;
struct vnode;
struct mbuf;
struct componentname;
struct ufs_lookup_results;
extern struct pool ext2fs_inode_pool; /* memory pool for inodes */
extern struct pool ext2fs_dinode_pool; /* memory pool for dinodes */
@@ -107,8 +108,10 @@ int ext2fs_gop_alloc(struct vnode *, off_t, off_t, int, kauth_cred_t);
int ext2fs_bmap(void *);
/* ext2fs_inode.c */
u_int64_t ext2fs_size(struct inode *);
int ext2fs_setsize(struct inode *, u_int64_t);
uint64_t ext2fs_size(struct inode *);
int ext2fs_setsize(struct inode *, uint64_t);
uint64_t ext2fs_nblock(struct inode *);
int ext2fs_setnblock(struct inode *, uint64_t);
int ext2fs_update(struct vnode *, const struct timespec *,
const struct timespec *, int);
int ext2fs_truncate(struct vnode *, off_t, int, kauth_cred_t);
+91 -34
View File
@@ -1,4 +1,4 @@
/* $NetBSD: ext2fs_inode.c,v 1.74 2011/06/16 09:21:03 hannken Exp $ */
/* $NetBSD: ext2fs_inode.c,v 1.81 2013/06/23 07:28:37 dholland Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@@ -60,7 +60,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ext2fs_inode.c,v 1.74 2011/06/16 09:21:03 hannken Exp $");
__KERNEL_RCSID(0, "$NetBSD: ext2fs_inode.c,v 1.81 2013/06/23 07:28:37 dholland Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -70,7 +70,7 @@ __KERNEL_RCSID(0, "$NetBSD: ext2fs_inode.c,v 1.74 2011/06/16 09:21:03 hannken Ex
#include <sys/buf.h>
#include <sys/vnode.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/kmem.h>
#include <sys/trace.h>
#include <sys/resourcevar.h>
#include <sys/kauth.h>
@@ -87,6 +87,14 @@ extern int prtactive;
static int ext2fs_indirtrunc(struct inode *, daddr_t, daddr_t,
daddr_t, int, long *);
/*
* These are fortunately the same values; it is likely that there is
* code that assumes they're equal. In any event, neither ought to
* ever change because it's a property of the on-disk formats.
*/
CTASSERT(EXT2FS_NDADDR == UFS_NDADDR);
CTASSERT(EXT2FS_NIADDR == UFS_NIADDR);
/*
* Get the size of an inode.
*/
@@ -128,6 +136,54 @@ ext2fs_setsize(struct inode *ip, uint64_t size)
return 0;
}
uint64_t
ext2fs_nblock(struct inode *ip)
{
uint64_t nblock = ip->i_e2fs_nblock;
struct m_ext2fs * const fs = ip->i_e2fs;
if (fs->e2fs.e2fs_features_rocompat & EXT2F_ROCOMPAT_HUGE_FILE) {
nblock |= (uint64_t)ip->i_e2fs_nblock_high << 32;
if ((ip->i_e2fs_flags & EXT2_HUGE_FILE)) {
nblock = EXT2_FSBTODB(fs, nblock);
}
}
return nblock;
}
int
ext2fs_setnblock(struct inode *ip, uint64_t nblock)
{
struct m_ext2fs * const fs = ip->i_e2fs;
if (nblock <= 0xffffffffULL) {
CLR(ip->i_e2fs_flags, EXT2_HUGE_FILE);
ip->i_e2fs_nblock = nblock;
return 0;
}
if (!ISSET(fs->e2fs.e2fs_features_rocompat, EXT2F_ROCOMPAT_HUGE_FILE))
return EFBIG;
if (nblock <= 0xffffffffffffULL) {
CLR(ip->i_e2fs_flags, EXT2_HUGE_FILE);
ip->i_e2fs_nblock = nblock & 0xffffffff;
ip->i_e2fs_nblock_high = (nblock >> 32) & 0xffff;
return 0;
}
if (EXT2_DBTOFSB(fs, nblock) <= 0xffffffffffffULL) {
SET(ip->i_e2fs_flags, EXT2_HUGE_FILE);
ip->i_e2fs_nblock = EXT2_DBTOFSB(fs, nblock) & 0xffffffff;
ip->i_e2fs_nblock_high = (EXT2_DBTOFSB(fs, nblock) >> 32) & 0xffff;
return 0;
}
return EFBIG;
}
/*
* Last reference to an inode. If necessary, write or delete it.
*/
@@ -205,10 +261,9 @@ ext2fs_update(struct vnode *vp, const struct timespec *acc,
fs = ip->i_e2fs;
error = bread(ip->i_devvp,
fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
EXT2_FSBTODB(fs, ino_to_fsba(fs, ip->i_number)),
(int)fs->e2fs_bsize, NOCRED, B_MODIFY, &bp);
if (error) {
brelse(bp, 0);
return (error);
}
ip->i_flag &= ~(IN_MODIFIED | IN_ACCESSED);
@@ -238,9 +293,9 @@ ext2fs_truncate(struct vnode *ovp, off_t length, int ioflag,
{
daddr_t lastblock;
struct inode *oip = VTOI(ovp);
daddr_t bn, lastiblock[NIADDR], indir_lbn[NIADDR];
daddr_t bn, lastiblock[EXT2FS_NIADDR], indir_lbn[EXT2FS_NIADDR];
/* XXX ondisk32 */
int32_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR];
int32_t oldblks[EXT2FS_NDADDR + EXT2FS_NIADDR], newblks[EXT2FS_NDADDR + EXT2FS_NIADDR];
struct m_ext2fs *fs;
int offset, size, level;
long count, blocksreleased = 0;
@@ -260,7 +315,7 @@ ext2fs_truncate(struct vnode *ovp, off_t length, int ioflag,
if (ovp->v_type == VLNK &&
(ext2fs_size(oip) < ump->um_maxsymlinklen ||
(ump->um_maxsymlinklen == 0 && oip->i_e2fs_nblock == 0))) {
(ump->um_maxsymlinklen == 0 && ext2fs_nblock(oip) == 0))) {
KDASSERT(length == 0);
memset((char *)&oip->i_din.e2fs_din->e2di_shortlink, 0,
(u_int)ext2fs_size(oip));
@@ -306,7 +361,7 @@ ext2fs_truncate(struct vnode *ovp, off_t length, int ioflag,
* zero'ed in case it ever become accessible again because
* of subsequent file growth.
*/
offset = blkoff(fs, length);
offset = ext2_blkoff(fs, length);
if (offset != 0) {
size = fs->e2fs_bsize;
@@ -322,10 +377,10 @@ ext2fs_truncate(struct vnode *ovp, off_t length, int ioflag,
* which we want to keep. Lastblock is -1 when
* the file is truncated to 0.
*/
lastblock = lblkno(fs, length + fs->e2fs_bsize - 1) - 1;
lastiblock[SINGLE] = lastblock - NDADDR;
lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
lastblock = ext2_lblkno(fs, length + fs->e2fs_bsize - 1) - 1;
lastiblock[SINGLE] = lastblock - EXT2FS_NDADDR;
lastiblock[DOUBLE] = lastiblock[SINGLE] - EXT2_NINDIR(fs);
lastiblock[TRIPLE] = lastiblock[DOUBLE] - EXT2_NINDIR(fs) * EXT2_NINDIR(fs);
nblocks = btodb(fs->e2fs_bsize);
/*
* Update file and block pointers on disk before we start freeing
@@ -336,13 +391,13 @@ ext2fs_truncate(struct vnode *ovp, off_t length, int ioflag,
memcpy((void *)oldblks, (void *)&oip->i_e2fs_blocks[0], sizeof oldblks);
sync = 0;
for (level = TRIPLE; level >= SINGLE; level--) {
if (lastiblock[level] < 0 && oldblks[NDADDR + level] != 0) {
if (lastiblock[level] < 0 && oldblks[EXT2FS_NDADDR + level] != 0) {
sync = 1;
oip->i_e2fs_blocks[NDADDR + level] = 0;
oip->i_e2fs_blocks[EXT2FS_NDADDR + level] = 0;
lastiblock[level] = -1;
}
}
for (i = 0; i < NDADDR; i++) {
for (i = 0; i < EXT2FS_NDADDR; i++) {
if (i > lastblock && oldblks[i] != 0) {
sync = 1;
oip->i_e2fs_blocks[i] = 0;
@@ -372,20 +427,20 @@ ext2fs_truncate(struct vnode *ovp, off_t length, int ioflag,
/*
* Indirect blocks first.
*/
indir_lbn[SINGLE] = -NDADDR;
indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) -1;
indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1;
indir_lbn[SINGLE] = -EXT2FS_NDADDR;
indir_lbn[DOUBLE] = indir_lbn[SINGLE] - EXT2_NINDIR(fs) -1;
indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - EXT2_NINDIR(fs) * EXT2_NINDIR(fs) - 1;
for (level = TRIPLE; level >= SINGLE; level--) {
/* XXX ondisk32 */
bn = fs2h32(oip->i_e2fs_blocks[NDADDR + level]);
bn = fs2h32(oip->i_e2fs_blocks[EXT2FS_NDADDR + level]);
if (bn != 0) {
error = ext2fs_indirtrunc(oip, indir_lbn[level],
fsbtodb(fs, bn), lastiblock[level], level, &count);
EXT2_FSBTODB(fs, bn), lastiblock[level], level, &count);
if (error)
allerror = error;
blocksreleased += count;
if (lastiblock[level] < 0) {
oip->i_e2fs_blocks[NDADDR + level] = 0;
oip->i_e2fs_blocks[EXT2FS_NDADDR + level] = 0;
ext2fs_blkfree(oip, bn);
blocksreleased += nblocks;
}
@@ -397,7 +452,7 @@ ext2fs_truncate(struct vnode *ovp, off_t length, int ioflag,
/*
* All whole direct blocks or frags.
*/
for (i = NDADDR - 1; i > lastblock; i--) {
for (i = EXT2FS_NDADDR - 1; i > lastblock; i--) {
/* XXX ondisk32 */
bn = fs2h32(oip->i_e2fs_blocks[i]);
if (bn == 0)
@@ -410,10 +465,10 @@ ext2fs_truncate(struct vnode *ovp, off_t length, int ioflag,
done:
#ifdef DIAGNOSTIC
for (level = SINGLE; level <= TRIPLE; level++)
if (newblks[NDADDR + level] !=
oip->i_e2fs_blocks[NDADDR + level])
if (newblks[EXT2FS_NDADDR + level] !=
oip->i_e2fs_blocks[EXT2FS_NDADDR + level])
panic("ext2fs_truncate1");
for (i = 0; i < NDADDR; i++)
for (i = 0; i < EXT2FS_NDADDR; i++)
if (newblks[i] != oip->i_e2fs_blocks[i])
panic("ext2fs_truncate2");
if (length == 0 &&
@@ -425,7 +480,9 @@ done:
* Put back the real size.
*/
(void)ext2fs_setsize(oip, length);
oip->i_e2fs_nblock -= blocksreleased;
error = ext2fs_setnblock(oip, ext2fs_nblock(oip) - blocksreleased);
if (error != 0)
allerror = error;
oip->i_flag |= IN_CHANGE;
KASSERT(ovp->v_type != VREG || ovp->v_size == ext2fs_size(oip));
return (allerror);
@@ -462,7 +519,7 @@ ext2fs_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn, daddr_t lastbn,
*/
factor = 1;
for (i = SINGLE; i < level; i++)
factor *= NINDIR(fs);
factor *= EXT2_NINDIR(fs);
last = lastbn;
if (lastbn > 0)
last /= factor;
@@ -499,10 +556,10 @@ ext2fs_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn, daddr_t lastbn,
bap = (int32_t *)bp->b_data; /* XXX ondisk32 */
if (lastbn >= 0) {
/* XXX ondisk32 */
copy = malloc(fs->e2fs_bsize, M_TEMP, M_WAITOK);
copy = kmem_alloc(fs->e2fs_bsize, KM_SLEEP);
memcpy((void *)copy, (void *)bap, (u_int)fs->e2fs_bsize);
memset((void *)&bap[last + 1], 0,
(u_int)(NINDIR(fs) - (last + 1)) * sizeof (uint32_t));
(u_int)(EXT2_NINDIR(fs) - (last + 1)) * sizeof (uint32_t));
error = bwrite(bp);
if (error)
allerror = error;
@@ -512,7 +569,7 @@ ext2fs_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn, daddr_t lastbn,
/*
* Recursively free totally unused blocks.
*/
for (i = NINDIR(fs) - 1,
for (i = EXT2_NINDIR(fs) - 1,
nlbn = lbn + 1 - i * factor; i > last;
i--, nlbn += factor) {
/* XXX ondisk32 */
@@ -520,7 +577,7 @@ ext2fs_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn, daddr_t lastbn,
if (nb == 0)
continue;
if (level > SINGLE) {
error = ext2fs_indirtrunc(ip, nlbn, fsbtodb(fs, nb),
error = ext2fs_indirtrunc(ip, nlbn, EXT2_FSBTODB(fs, nb),
(daddr_t)-1, level - 1,
&blkcount);
if (error)
@@ -539,7 +596,7 @@ ext2fs_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn, daddr_t lastbn,
/* XXX ondisk32 */
nb = fs2h32(bap[i]);
if (nb != 0) {
error = ext2fs_indirtrunc(ip, nlbn, fsbtodb(fs, nb),
error = ext2fs_indirtrunc(ip, nlbn, EXT2_FSBTODB(fs, nb),
last, level - 1, &blkcount);
if (error)
allerror = error;
@@ -548,7 +605,7 @@ ext2fs_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn, daddr_t lastbn,
}
if (copy != NULL) {
free(copy, M_TEMP);
kmem_free(copy, fs->e2fs_bsize);
} else {
brelse(bp, BC_INVAL);
}
+50 -35
View File
@@ -1,4 +1,4 @@
/* $NetBSD: ext2fs_lookup.c,v 1.66 2011/07/12 16:59:48 dholland Exp $ */
/* $NetBSD: ext2fs_lookup.c,v 1.73 2013/01/22 09:39:15 dholland Exp $ */
/*
* Modified for NetBSD 1.2E
@@ -48,7 +48,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ext2fs_lookup.c,v 1.66 2011/07/12 16:59:48 dholland Exp $");
__KERNEL_RCSID(0, "$NetBSD: ext2fs_lookup.c,v 1.73 2013/01/22 09:39:15 dholland Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -57,6 +57,7 @@ __KERNEL_RCSID(0, "$NetBSD: ext2fs_lookup.c,v 1.66 2011/07/12 16:59:48 dholland
#include <sys/file.h>
#include <sys/mount.h>
#include <sys/vnode.h>
#include <sys/kmem.h>
#include <sys/malloc.h>
#include <sys/dirent.h>
#include <sys/kauth.h>
@@ -70,6 +71,8 @@ __KERNEL_RCSID(0, "$NetBSD: ext2fs_lookup.c,v 1.66 2011/07/12 16:59:48 dholland
#include <ufs/ext2fs/ext2fs_dir.h>
#include <ufs/ext2fs/ext2fs.h>
#include <miscfs/genfs/genfs.h>
extern int dirchk;
static void ext2fs_dirconv2ffs(struct ext2fs_direct *e2dir,
@@ -167,15 +170,14 @@ ext2fs_readdir(void *v)
aiov.iov_len = e2fs_count;
auio.uio_resid = e2fs_count;
UIO_SETUP_SYSSPACE(&auio);
dirbuf = malloc(e2fs_count, M_TEMP, M_WAITOK);
dstd = malloc(sizeof(struct dirent), M_TEMP, M_WAITOK | M_ZERO);
dirbuf = kmem_alloc(e2fs_count, KM_SLEEP);
dstd = kmem_zalloc(sizeof(struct dirent), KM_SLEEP);
if (ap->a_ncookies) {
nc = e2fs_count / _DIRENT_MINSIZE((struct dirent *)0);
ncookies = nc;
cookies = malloc(sizeof (off_t) * ncookies, M_TEMP, M_WAITOK);
*ap->a_cookies = cookies;
}
memset(dirbuf, 0, e2fs_count);
aiov.iov_base = dirbuf;
error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred);
@@ -209,8 +211,8 @@ ext2fs_readdir(void *v)
/* we need to correct uio_offset */
uio->uio_offset = off;
}
free(dirbuf, M_TEMP);
free(dstd, M_TEMP);
kmem_free(dirbuf, e2fs_count);
kmem_free(dstd, sizeof(*dstd));
*ap->a_eofflag = ext2fs_size(VTOI(ap->a_vp)) <= uio->uio_offset;
if (ap->a_ncookies) {
if (error) {
@@ -323,8 +325,10 @@ ext2fs_lookup(void *v)
* check the name cache to see if the directory/name pair
* we are looking for is known already.
*/
if ((error = cache_lookup(vdp, vpp, cnp)) >= 0)
return (error);
if (cache_lookup(vdp, cnp->cn_nameptr, cnp->cn_namelen,
cnp->cn_nameiop, cnp->cn_flags, NULL, vpp)) {
return *vpp == NULLVP ? ENOENT : 0;
}
/*
* Suppress search for slots unless creating
@@ -536,9 +540,11 @@ searchloop:
/*
* Insert name into cache (as non-existent) if appropriate.
*/
if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
cache_enter(vdp, *vpp, cnp);
return (ENOENT);
if (nameiop != CREATE) {
cache_enter(vdp, *vpp, cnp->cn_nameptr, cnp->cn_namelen,
cnp->cn_flags);
}
return ENOENT;
found:
if (numdirpasses == 2)
@@ -574,11 +580,6 @@ found:
* Lock the inode, being careful with ".".
*/
if (nameiop == DELETE && (flags & ISLASTCN)) {
/*
* Write access to directory required to delete files.
*/
if ((error = VOP_ACCESS(vdp, VWRITE, cred)) != 0)
return (error);
/*
* Return pointer to current entry in results->ulr_offset,
* and distance past previous entry (if there
@@ -591,28 +592,43 @@ found:
results->ulr_count = results->ulr_offset - prevoff;
if (dp->i_number == foundino) {
vref(vdp);
*vpp = vdp;
return (0);
tdp = vdp;
} else {
if (flags & ISDOTDOT)
VOP_UNLOCK(vdp); /* race to get the inode */
error = VFS_VGET(vdp->v_mount, foundino, &tdp);
if (flags & ISDOTDOT)
vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY);
if (error)
return (error);
}
if (flags & ISDOTDOT)
VOP_UNLOCK(vdp); /* race to get the inode */
error = VFS_VGET(vdp->v_mount, foundino, &tdp);
if (flags & ISDOTDOT)
vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY);
if (error)
/*
* Write access to directory required to delete files.
*/
if ((error = VOP_ACCESS(vdp, VWRITE, cred)) != 0) {
if (dp->i_number == foundino)
vrele(tdp);
else
vput(tdp);
return (error);
}
/*
* If directory is "sticky", then user must own
* the directory, or the file in it, else she
* may not delete it (unless she's root). This
* implements append-only directories.
*/
if ((dp->i_e2fs_mode & ISVTX) &&
kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL) &&
kauth_cred_geteuid(cred) != dp->i_uid &&
VTOI(tdp)->i_uid != kauth_cred_geteuid(cred)) {
vput(tdp);
return (EPERM);
if (dp->i_e2fs_mode & ISVTX) {
error = kauth_authorize_vnode(cred, KAUTH_VNODE_DELETE,
tdp, vdp, genfs_can_sticky(cred, dp->i_uid,
VTOI(tdp)->i_uid));
if (error) {
if (dp->i_number == foundino)
vrele(tdp);
else
vput(tdp);
return (EPERM);
}
}
*vpp = tdp;
return (0);
@@ -686,9 +702,8 @@ found:
/*
* Insert name into cache if appropriate.
*/
if (cnp->cn_flags & MAKEENTRY)
cache_enter(vdp, *vpp, cnp);
return (0);
cache_enter(vdp, *vpp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_flags);
return 0;
}
/*
@@ -1030,7 +1045,7 @@ ext2fs_checkpath(struct inode *source, struct inode *target,
error = EEXIST;
goto out;
}
rootino = ROOTINO;
rootino = UFS_ROOTINO;
error = 0;
if (target->i_number == rootino)
goto out;
+25 -14
View File
@@ -1,4 +1,4 @@
/* $NetBSD: ext2fs_readwrite.c,v 1.58 2011/11/18 21:18:51 christos Exp $ */
/* $NetBSD: ext2fs_readwrite.c,v 1.64 2013/06/23 07:28:37 dholland Exp $ */
/*-
* Copyright (c) 1993
@@ -60,7 +60,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ext2fs_readwrite.c,v 1.58 2011/11/18 21:18:51 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: ext2fs_readwrite.c,v 1.64 2013/06/23 07:28:37 dholland Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -123,7 +123,7 @@ ext2fs_read(void *v)
if (vp->v_type == VLNK) {
if (ext2fs_size(ip) < ump->um_maxsymlinklen ||
(ump->um_maxsymlinklen == 0 && ip->i_e2fs_nblock == 0))
(ump->um_maxsymlinklen == 0 && ext2fs_nblock(ip) == 0))
panic("%s: short symlink", "ext2fs_read");
} else if (vp->v_type != VREG && vp->v_type != VDIR)
panic("%s: type %d", "ext2fs_read", vp->v_type);
@@ -157,17 +157,17 @@ ext2fs_read(void *v)
bytesinfile = ext2fs_size(ip) - uio->uio_offset;
if (bytesinfile <= 0)
break;
lbn = lblkno(fs, uio->uio_offset);
lbn = ext2_lblkno(fs, uio->uio_offset);
nextlbn = lbn + 1;
size = fs->e2fs_bsize;
blkoffset = blkoff(fs, uio->uio_offset);
blkoffset = ext2_blkoff(fs, uio->uio_offset);
xfersize = fs->e2fs_bsize - blkoffset;
if (uio->uio_resid < xfersize)
xfersize = uio->uio_resid;
if (bytesinfile < xfersize)
xfersize = bytesinfile;
if (lblktosize(fs, nextlbn) >= ext2fs_size(ip))
if (ext2_lblktosize(fs, nextlbn) >= ext2fs_size(ip))
error = bread(vp, lbn, size, NOCRED, 0, &bp);
else {
int nextsize = fs->e2fs_bsize;
@@ -279,7 +279,7 @@ ext2fs_write(void *v)
if (vp->v_type == VREG) {
while (uio->uio_resid > 0) {
oldoff = uio->uio_offset;
blkoffset = blkoff(fs, uio->uio_offset);
blkoffset = ext2_blkoff(fs, uio->uio_offset);
bytelen = MIN(fs->e2fs_bsize - blkoffset,
uio->uio_resid);
@@ -313,13 +313,14 @@ ext2fs_write(void *v)
if (!async && oldoff >> 16 != uio->uio_offset >> 16) {
mutex_enter(vp->v_interlock);
error = VOP_PUTPAGES(vp, (oldoff >> 16) << 16,
(uio->uio_offset >> 16) << 16, PGO_CLEANIT);
(uio->uio_offset >> 16) << 16,
PGO_CLEANIT | PGO_LAZY);
}
}
if (error == 0 && ioflag & IO_SYNC) {
mutex_enter(vp->v_interlock);
error = VOP_PUTPAGES(vp, trunc_page(oldoff),
round_page(blkroundup(fs, uio->uio_offset)),
round_page(ext2_blkroundup(fs, uio->uio_offset)),
PGO_CLEANIT | PGO_SYNCIO);
}
@@ -328,8 +329,8 @@ ext2fs_write(void *v)
flags = ioflag & IO_SYNC ? B_SYNC : 0;
for (error = 0; uio->uio_resid > 0;) {
lbn = lblkno(fs, uio->uio_offset);
blkoffset = blkoff(fs, uio->uio_offset);
lbn = ext2_lblkno(fs, uio->uio_offset);
blkoffset = ext2_blkoff(fs, uio->uio_offset);
xfersize = MIN(fs->e2fs_bsize - blkoffset, uio->uio_resid);
if (xfersize < fs->e2fs_bsize)
flags |= B_CLRBUF;
@@ -376,9 +377,19 @@ out:
ip->i_flag |= IN_CHANGE | IN_UPDATE;
if (vp->v_mount->mnt_flag & MNT_RELATIME)
ip->i_flag |= IN_ACCESS;
if (resid > uio->uio_resid && ap->a_cred &&
kauth_authorize_generic(ap->a_cred, KAUTH_GENERIC_ISSUSER, NULL))
ip->i_e2fs_mode &= ~(ISUID | ISGID);
if (resid > uio->uio_resid && ap->a_cred) {
if (ip->i_e2fs_mode & ISUID) {
if (kauth_authorize_vnode(ap->a_cred,
KAUTH_VNODE_RETAIN_SUID, vp, NULL, EPERM) != 0)
ip->i_e2fs_mode &= ISUID;
}
if (ip->i_e2fs_mode & ISGID) {
if (kauth_authorize_vnode(ap->a_cred,
KAUTH_VNODE_RETAIN_SGID, vp, NULL, EPERM) != 0)
ip->i_e2fs_mode &= ~ISGID;
}
}
if (resid > uio->uio_resid)
VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0));
if (error) {
+992
View File
@@ -0,0 +1,992 @@
/* $NetBSD: ext2fs_rename.c,v 1.5 2013/01/22 09:39:15 dholland Exp $ */
/*-
* Copyright (c) 2012 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Taylor R Campbell.
*
* 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``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 FOUNDATION OR CONTRIBUTORS
* 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.
*/
/*
* Ext2fs Rename
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ext2fs_rename.c,v 1.5 2013/01/22 09:39:15 dholland Exp $");
#include <sys/param.h>
#include <sys/buf.h>
#include <sys/errno.h>
#include <sys/kauth.h>
#include <sys/mount.h>
#include <sys/namei.h>
#include <sys/vnode.h>
#include <sys/vnode_if.h>
#include <miscfs/genfs/genfs.h>
#include <ufs/ext2fs/ext2fs.h>
#include <ufs/ext2fs/ext2fs_dir.h>
#include <ufs/ext2fs/ext2fs_extern.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufs_extern.h>
#include <ufs/ufs/ufsmount.h>
/*
* Forward declarations
*/
static int ext2fs_sane_rename(struct vnode *, struct componentname *,
struct vnode *, struct componentname *,
kauth_cred_t, bool);
static bool ext2fs_rename_ulr_overlap_p(const struct ufs_lookup_results *,
const struct ufs_lookup_results *);
static int ext2fs_rename_recalculate_fulr(struct vnode *,
struct ufs_lookup_results *, const struct ufs_lookup_results *,
const struct componentname *);
static bool ext2fs_rmdired_p(struct vnode *);
static int ext2fs_read_dotdot(struct vnode *, kauth_cred_t, ino_t *);
static int ext2fs_rename_replace_dotdot(struct vnode *,
struct vnode *, struct vnode *, kauth_cred_t);
static int ext2fs_gro_lock_directory(struct mount *, struct vnode *);
static const struct genfs_rename_ops ext2fs_genfs_rename_ops;
/*
* ext2fs_sane_rename: The hairiest vop, with the saner API.
*
* Arguments:
*
* . fdvp (from directory vnode),
* . fcnp (from component name),
* . tdvp (to directory vnode),
* . tcnp (to component name),
* . cred (credentials structure), and
* . posixly_correct (flag for behaviour if target & source link same file).
*
* fdvp and tdvp may be the same, and must be referenced and unlocked.
*/
static int
ext2fs_sane_rename(
struct vnode *fdvp, struct componentname *fcnp,
struct vnode *tdvp, struct componentname *tcnp,
kauth_cred_t cred, bool posixly_correct)
{
struct ufs_lookup_results fulr, tulr;
return genfs_sane_rename(&ext2fs_genfs_rename_ops,
fdvp, fcnp, &fulr, tdvp, tcnp, &tulr,
cred, posixly_correct);
}
/*
* ext2fs_rename: The hairiest vop, with the insanest API. Defer to
* genfs_insane_rename immediately.
*/
int
ext2fs_rename(void *v)
{
return genfs_insane_rename(v, &ext2fs_sane_rename);
}
/*
* ext2fs_gro_directory_empty_p: Return true if the directory vp is
* empty. dvp is its parent.
*
* vp and dvp must be locked and referenced.
*/
static bool
ext2fs_gro_directory_empty_p(struct mount *mp, kauth_cred_t cred,
struct vnode *vp, struct vnode *dvp)
{
(void)mp;
KASSERT(mp != NULL);
KASSERT(vp != NULL);
KASSERT(dvp != NULL);
KASSERT(vp != dvp);
KASSERT(vp->v_mount == mp);
KASSERT(dvp->v_mount == mp);
KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
return ext2fs_dirempty(VTOI(vp), VTOI(dvp)->i_number, cred);
}
/*
* ext2fs_gro_rename_check_possible: Check whether a rename is possible
* independent of credentials.
*/
static int
ext2fs_gro_rename_check_possible(struct mount *mp,
struct vnode *fdvp, struct vnode *fvp,
struct vnode *tdvp, struct vnode *tvp)
{
(void)mp;
KASSERT(mp != NULL);
KASSERT(fdvp != NULL);
KASSERT(fvp != NULL);
KASSERT(tdvp != NULL);
KASSERT(fdvp != fvp);
KASSERT(fdvp != tvp);
KASSERT(tdvp != fvp);
KASSERT(tdvp != tvp);
KASSERT(fvp != tvp);
KASSERT(fdvp->v_type == VDIR);
KASSERT(tdvp->v_type == VDIR);
KASSERT(fdvp->v_mount == mp);
KASSERT(fvp->v_mount == mp);
KASSERT(tdvp->v_mount == mp);
KASSERT((tvp == NULL) || (tvp->v_mount == mp));
KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
return genfs_ufslike_rename_check_possible(
VTOI(fdvp)->i_e2fs_flags, VTOI(fvp)->i_e2fs_flags,
VTOI(tdvp)->i_e2fs_flags, (tvp? VTOI(tvp)->i_e2fs_flags : 0),
(tvp != NULL),
EXT2_IMMUTABLE, EXT2_APPEND);
}
/*
* ext2fs_gro_rename_check_permitted: Check whether a rename is
* permitted given our credentials.
*/
static int
ext2fs_gro_rename_check_permitted(struct mount *mp, kauth_cred_t cred,
struct vnode *fdvp, struct vnode *fvp,
struct vnode *tdvp, struct vnode *tvp)
{
(void)mp;
KASSERT(mp != NULL);
KASSERT(fdvp != NULL);
KASSERT(fvp != NULL);
KASSERT(tdvp != NULL);
KASSERT(fdvp != fvp);
KASSERT(fdvp != tvp);
KASSERT(tdvp != fvp);
KASSERT(tdvp != tvp);
KASSERT(fvp != tvp);
KASSERT(fdvp->v_type == VDIR);
KASSERT(tdvp->v_type == VDIR);
KASSERT(fdvp->v_mount == mp);
KASSERT(fvp->v_mount == mp);
KASSERT(tdvp->v_mount == mp);
KASSERT((tvp == NULL) || (tvp->v_mount == mp));
KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
return genfs_ufslike_rename_check_permitted(cred,
fdvp, VTOI(fdvp)->i_e2fs_mode, VTOI(fdvp)->i_uid,
fvp, VTOI(fvp)->i_uid,
tdvp, VTOI(tdvp)->i_e2fs_mode, VTOI(tdvp)->i_uid,
tvp, (tvp? VTOI(tvp)->i_uid : 0));
}
/*
* ext2fs_gro_remove_check_possible: Check whether a remove is possible
* independent of credentials.
*/
static int
ext2fs_gro_remove_check_possible(struct mount *mp,
struct vnode *dvp, struct vnode *vp)
{
(void)mp;
KASSERT(mp != NULL);
KASSERT(dvp != NULL);
KASSERT(vp != NULL);
KASSERT(dvp != vp);
KASSERT(dvp->v_type == VDIR);
KASSERT(vp->v_type != VDIR);
KASSERT(dvp->v_mount == mp);
KASSERT(vp->v_mount == mp);
KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
return genfs_ufslike_remove_check_possible(
VTOI(dvp)->i_e2fs_flags, VTOI(vp)->i_e2fs_flags,
EXT2_IMMUTABLE, EXT2_APPEND);
}
/*
* ext2fs_gro_remove_check_permitted: Check whether a remove is
* permitted given our credentials.
*/
static int
ext2fs_gro_remove_check_permitted(struct mount *mp, kauth_cred_t cred,
struct vnode *dvp, struct vnode *vp)
{
(void)mp;
KASSERT(mp != NULL);
KASSERT(dvp != NULL);
KASSERT(vp != NULL);
KASSERT(dvp != vp);
KASSERT(dvp->v_type == VDIR);
KASSERT(vp->v_type != VDIR);
KASSERT(dvp->v_mount == mp);
KASSERT(vp->v_mount == mp);
KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
return genfs_ufslike_remove_check_permitted(cred,
dvp, VTOI(dvp)->i_e2fs_mode, VTOI(dvp)->i_uid,
vp, VTOI(vp)->i_uid);
}
/*
* ext2fs_gro_rename: Actually perform the rename operation.
*/
static int
ext2fs_gro_rename(struct mount *mp, kauth_cred_t cred,
struct vnode *fdvp, struct componentname *fcnp,
void *fde, struct vnode *fvp,
struct vnode *tdvp, struct componentname *tcnp,
void *tde, struct vnode *tvp)
{
struct ufs_lookup_results *fulr = fde;
struct ufs_lookup_results *tulr = tde;
bool directory_p, reparent_p;
int error;
(void)mp;
KASSERT(mp != NULL);
KASSERT(fdvp != NULL);
KASSERT(fcnp != NULL);
KASSERT(fulr != NULL);
KASSERT(fvp != NULL);
KASSERT(tdvp != NULL);
KASSERT(tcnp != NULL);
KASSERT(tulr != NULL);
KASSERT(fulr != tulr);
KASSERT(fdvp != fvp);
KASSERT(fdvp != tvp);
KASSERT(tdvp != fvp);
KASSERT(tdvp != tvp);
KASSERT(fvp != tvp);
KASSERT(fdvp->v_mount == mp);
KASSERT(fvp->v_mount == mp);
KASSERT(tdvp->v_mount == mp);
KASSERT((tvp == NULL) || (tvp->v_mount == mp));
KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
/*
* We shall need to temporarily bump the link count, so make
* sure there is room to do so.
*/
if ((nlink_t)VTOI(fvp)->i_e2fs_nlink >= LINK_MAX)
return EMLINK;
directory_p = (fvp->v_type == VDIR);
KASSERT(directory_p == ((VTOI(fvp)->i_e2fs_mode & IFMT) == IFDIR));
KASSERT((tvp == NULL) || (directory_p == (tvp->v_type == VDIR)));
KASSERT((tvp == NULL) || (directory_p ==
((VTOI(tvp)->i_e2fs_mode & IFMT) == IFDIR)));
reparent_p = (fdvp != tdvp);
KASSERT(reparent_p == (VTOI(fdvp)->i_number != VTOI(tdvp)->i_number));
/*
* Commence hacking of the data on disk.
*/
/*
* 1) Bump link count while we're moving stuff
* around. If we crash somewhere before
* completing our work, the link count
* may be wrong, but correctable.
*/
KASSERT((nlink_t)VTOI(fvp)->i_e2fs_nlink < LINK_MAX);
VTOI(fvp)->i_e2fs_nlink++;
VTOI(fvp)->i_flag |= IN_CHANGE;
error = ext2fs_update(fvp, NULL, NULL, UPDATE_WAIT);
if (error)
goto whymustithurtsomuch;
/*
* 2) If target doesn't exist, link the target
* to the source and unlink the source.
* Otherwise, rewrite the target directory
* entry to reference the source inode and
* expunge the original entry's existence.
*/
if (tvp == NULL) {
/*
* Account for ".." in new directory.
* When source and destination have the same
* parent we don't fool with the link count.
*/
if (directory_p && reparent_p) {
if ((nlink_t)VTOI(tdvp)->i_e2fs_nlink >= LINK_MAX) {
error = EMLINK;
goto whymustithurtsomuch;
}
KASSERT((nlink_t)VTOI(tdvp)->i_e2fs_nlink < LINK_MAX);
VTOI(tdvp)->i_e2fs_nlink++;
VTOI(tdvp)->i_flag |= IN_CHANGE;
error = ext2fs_update(tdvp, NULL, NULL, UPDATE_WAIT);
if (error) {
/*
* Link count update didn't take --
* back out the in-memory link count.
*/
KASSERT(0 < VTOI(tdvp)->i_e2fs_nlink);
VTOI(tdvp)->i_e2fs_nlink--;
VTOI(tdvp)->i_flag |= IN_CHANGE;
goto whymustithurtsomuch;
}
}
error = ext2fs_direnter(VTOI(fvp), tdvp, tulr, tcnp);
if (error) {
if (directory_p && reparent_p) {
/*
* Directory update didn't take, but
* the link count update did -- back
* out the in-memory link count and the
* on-disk link count.
*/
KASSERT(0 < VTOI(tdvp)->i_e2fs_nlink);
VTOI(tdvp)->i_e2fs_nlink--;
VTOI(tdvp)->i_flag |= IN_CHANGE;
(void)ext2fs_update(tdvp, NULL, NULL,
UPDATE_WAIT);
}
goto whymustithurtsomuch;
}
} else {
if (directory_p)
/* XXX WTF? Why purge here? Why not purge others? */
cache_purge(tdvp);
/*
* Make the target directory's entry for tcnp point at
* the source node.
*/
error = ext2fs_dirrewrite(VTOI(tdvp), tulr, VTOI(fvp), tcnp);
if (error)
goto whymustithurtsomuch;
/*
* If the source and target are directories, and the
* target is in the same directory as the source,
* decrement the link count of the common parent
* directory, since we are removing the target from
* that directory.
*/
if (directory_p && !reparent_p) {
KASSERT(fdvp == tdvp);
/* XXX check, don't kassert */
KASSERT(0 < VTOI(tdvp)->i_e2fs_nlink);
VTOI(tdvp)->i_e2fs_nlink--;
VTOI(tdvp)->i_flag |= IN_CHANGE;
}
/*
* Adjust the link count of the target to
* reflect the dirrewrite above. If this is
* a directory it is empty and there are
* no links to it, so we can squash the inode and
* any space associated with it. We disallowed
* renaming over top of a directory with links to
* it above, as the remaining link would point to
* a directory without "." or ".." entries.
*/
/* XXX check, don't kassert */
KASSERT(0 < VTOI(tvp)->i_e2fs_nlink);
VTOI(tvp)->i_e2fs_nlink--;
if (directory_p) {
/*
* XXX The ext2fs_dirempty call earlier does
* not guarantee anything about nlink.
*/
if (VTOI(tvp)->i_e2fs_nlink != 1)
ufs_dirbad(VTOI(tvp), (doff_t)0,
"hard-linked directory");
VTOI(tvp)->i_e2fs_nlink = 0;
error = ext2fs_truncate(tvp, (off_t)0, IO_SYNC, cred);
#if 0 /* XXX This branch was not in ext2fs_rename! */
if (error)
goto whymustithurtsomuch;
#endif
}
/*
* XXX Why is this here, and not above the preceding
* conditional?
*/
VTOI(tvp)->i_flag |= IN_CHANGE;
}
/*
* If the source is a directory with a new parent, the link
* count of the old parent directory must be decremented and
* ".." set to point to the new parent.
*/
if (directory_p && reparent_p) {
error = ext2fs_rename_replace_dotdot(fvp, fdvp, tdvp, cred);
if (error)
goto whymustithurtsomuch;
/* XXX WTF? Why purge here? Why not purge others? */
cache_purge(fdvp);
}
/*
* 3) Unlink the source.
*/
/*
* ext2fs_direnter may compact the directory in the process of
* inserting a new entry. That may invalidate fulr, which we
* need in order to remove the old entry. In that case, we
* need to recalculate what fulr should be.
*/
if (!reparent_p && (tvp == NULL) &&
ext2fs_rename_ulr_overlap_p(fulr, tulr)) {
error = ext2fs_rename_recalculate_fulr(fdvp, fulr, tulr, fcnp);
#if 0 /* XXX */
if (error) /* XXX Try to back out changes? */
goto whymustithurtsomuch;
#endif
}
error = ext2fs_dirremove(fdvp, fulr, fcnp);
if (error)
goto whymustithurtsomuch;
/*
* XXX Perhaps this should go at the top, in case the file
* system is modified but incompletely so because of an
* intermediate error.
*/
genfs_rename_knote(fdvp, fvp, tdvp, tvp,
((tvp != NULL) && (VTOI(tvp)->i_e2fs_nlink == 0)));
#if 0 /* XXX */
genfs_rename_cache_purge(fdvp, fvp, tdvp, tvp);
#endif
whymustithurtsomuch:
KASSERT(0 < VTOI(fvp)->i_e2fs_nlink);
VTOI(fvp)->i_e2fs_nlink--;
VTOI(fvp)->i_flag |= IN_CHANGE;
return error;
}
/*
* ext2fs_rename_ulr_overlap_p: True iff tulr overlaps with fulr so
* that entering a directory entry at tulr may move fulr.
*/
static bool
ext2fs_rename_ulr_overlap_p(const struct ufs_lookup_results *fulr,
const struct ufs_lookup_results *tulr)
{
doff_t from_prev_start, from_prev_end, to_start, to_end;
KASSERT(fulr != NULL);
KASSERT(tulr != NULL);
KASSERT(fulr != tulr);
/*
* fulr is from a DELETE lookup, so fulr->ulr_count is the size
* of the preceding entry (d_reclen).
*/
from_prev_end = fulr->ulr_offset;
KASSERT(fulr->ulr_count <= from_prev_end);
from_prev_start = (from_prev_end - fulr->ulr_count);
/*
* tulr is from a RENAME lookup, so tulr->ulr_count is the size
* of the free space for an entry that we are about to fill.
*/
to_start = tulr->ulr_offset;
KASSERT(tulr->ulr_count < (EXT2FS_MAXDIRSIZE - to_start));
to_end = (to_start + tulr->ulr_count);
return
(((to_start <= from_prev_start) && (from_prev_start < to_end)) ||
((to_start <= from_prev_end) && (from_prev_end < to_end)));
}
/*
* ext2fs_rename_recalculate_fulr: If we have just entered a directory
* into dvp at tulr, and we were about to remove one at fulr for an
* entry named fcnp, fulr may be invalid. So, if necessary,
* recalculate it.
*/
static int
ext2fs_rename_recalculate_fulr(struct vnode *dvp,
struct ufs_lookup_results *fulr, const struct ufs_lookup_results *tulr,
const struct componentname *fcnp)
{
struct mount *mp;
struct ufsmount *ump;
/* XXX int is a silly type for this; blame ufsmount::um_dirblksiz. */
int dirblksiz;
doff_t search_start, search_end;
doff_t offset; /* Offset of entry we're examining. */
struct buf *bp; /* I/O block we're examining. */
char *dirbuf; /* Pointer into directory at search_start. */
struct ext2fs_direct *ep; /* Pointer to the entry we're examining. */
/* XXX direct::d_reclen is 16-bit;
* ufs_lookup_results::ulr_reclen is 32-bit. Blah. */
uint32_t reclen; /* Length of the entry we're examining. */
uint32_t prev_reclen; /* Length of the preceding entry. */
int error;
KASSERT(dvp != NULL);
KASSERT(dvp->v_mount != NULL);
KASSERT(VTOI(dvp) != NULL);
KASSERT(fulr != NULL);
KASSERT(tulr != NULL);
KASSERT(fulr != tulr);
KASSERT(ext2fs_rename_ulr_overlap_p(fulr, tulr));
mp = dvp->v_mount;
ump = VFSTOUFS(mp);
KASSERT(ump != NULL);
KASSERT(ump == VTOI(dvp)->i_ump);
dirblksiz = ump->um_dirblksiz;
KASSERT(0 < dirblksiz);
KASSERT((dirblksiz & (dirblksiz - 1)) == 0);
/* A directory block may not span across multiple I/O blocks. */
KASSERT(dirblksiz <= mp->mnt_stat.f_iosize);
/* Find the bounds of the search. */
search_start = tulr->ulr_offset;
KASSERT(fulr->ulr_reclen < (EXT2FS_MAXDIRSIZE - fulr->ulr_offset));
search_end = (fulr->ulr_offset + fulr->ulr_reclen);
/* Compaction must happen only within a directory block. (*) */
KASSERT(search_start <= search_end);
KASSERT((search_end - (search_start &~ (dirblksiz - 1))) <= dirblksiz);
dirbuf = NULL;
bp = NULL;
error = ext2fs_blkatoff(dvp, (off_t)search_start, &dirbuf, &bp);
if (error)
return error;
KASSERT(dirbuf != NULL);
KASSERT(bp != NULL);
/*
* Guarantee we sha'n't go past the end of the buffer we got.
* dirbuf is bp->b_data + (search_start & (iosize - 1)), and
* the valid range is [bp->b_data, bp->b_data + bp->b_bcount).
*/
KASSERT((search_end - search_start) <=
(bp->b_bcount - (search_start & (mp->mnt_stat.f_iosize - 1))));
prev_reclen = fulr->ulr_count;
offset = search_start;
/*
* Search from search_start to search_end for the entry matching
* fcnp, which must be there because we found it before and it
* should only at most have moved earlier.
*/
for (;;) {
KASSERT(search_start <= offset);
KASSERT(offset < search_end);
/*
* Examine the directory entry at offset.
*/
ep = (struct ext2fs_direct *)
(dirbuf + (offset - search_start));
reclen = fs2h16(ep->e2d_reclen);
if (ep->e2d_ino == 0)
goto next; /* Entry is unused. */
if (fs2h32(ep->e2d_ino) == UFS_WINO)
goto next; /* Entry is whiteout. */
if (fcnp->cn_namelen != ep->e2d_namlen)
goto next; /* Wrong name length. */
if (memcmp(ep->e2d_name, fcnp->cn_nameptr, fcnp->cn_namelen))
goto next; /* Wrong name. */
/* Got it! */
break;
next:
if (! ((reclen < search_end) &&
(offset < (search_end - reclen)))) {
brelse(bp, 0);
return EIO; /* XXX Panic? What? */
}
/* We may not move past the search end. */
KASSERT(reclen < search_end);
KASSERT(offset < (search_end - reclen));
/*
* We may not move across a directory block boundary;
* see (*) above.
*/
KASSERT((offset &~ (dirblksiz - 1)) ==
((offset + reclen) &~ (dirblksiz - 1)));
prev_reclen = reclen;
offset += reclen;
}
/*
* Found the entry. Record where.
*/
fulr->ulr_offset = offset;
fulr->ulr_reclen = reclen;
/*
* Record the preceding record length, but not if we're at the
* start of a directory block.
*/
fulr->ulr_count = ((offset & (dirblksiz - 1))? prev_reclen : 0);
brelse(bp, 0);
return 0;
}
/*
* ext2fs_gro_remove: Rename an object over another link to itself,
* effectively removing just the original link.
*/
static int
ext2fs_gro_remove(struct mount *mp, kauth_cred_t cred,
struct vnode *dvp, struct componentname *cnp, void *de, struct vnode *vp)
{
struct ufs_lookup_results *ulr = de;
int error;
(void)mp;
KASSERT(mp != NULL);
KASSERT(dvp != NULL);
KASSERT(cnp != NULL);
KASSERT(ulr != NULL);
KASSERT(vp != NULL);
KASSERT(dvp != vp);
KASSERT(dvp->v_mount == mp);
KASSERT(vp->v_mount == mp);
KASSERT(dvp->v_type == VDIR);
KASSERT(vp->v_type != VDIR);
KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
error = ext2fs_dirremove(dvp, ulr, cnp);
if (error)
return error;
KASSERT(0 < VTOI(vp)->i_e2fs_nlink);
VTOI(vp)->i_e2fs_nlink--;
VTOI(vp)->i_flag |= IN_CHANGE;
VN_KNOTE(dvp, NOTE_WRITE);
VN_KNOTE(vp, (VTOI(vp)->i_e2fs_nlink? NOTE_LINK : NOTE_DELETE));
return 0;
}
/*
* ext2fs_gro_lookup: Look up and save the lookup results.
*/
static int
ext2fs_gro_lookup(struct mount *mp, struct vnode *dvp,
struct componentname *cnp, void *de_ret, struct vnode **vp_ret)
{
struct ufs_lookup_results *ulr_ret = de_ret;
struct vnode *vp;
int error;
(void)mp;
KASSERT(mp != NULL);
KASSERT(dvp != NULL);
KASSERT(cnp != NULL);
KASSERT(ulr_ret != NULL);
KASSERT(vp_ret != NULL);
KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
/* Kludge cargo-culted from dholland's ufs_rename. */
cnp->cn_flags &=~ MODMASK;
cnp->cn_flags |= (LOCKPARENT | LOCKLEAF);
error = relookup(dvp, &vp, cnp, 0 /* dummy */);
if ((error == 0) && (vp == NULL)) {
error = ENOENT;
goto out;
} else if (error) {
return error;
}
/*
* Thanks to VFS insanity, relookup locks vp, which screws us
* in various ways.
*/
KASSERT(vp != NULL);
VOP_UNLOCK(vp);
out: *ulr_ret = VTOI(dvp)->i_crap;
*vp_ret = vp;
return error;
}
/*
* ext2fs_rmdired_p: Check whether the directory vp has been rmdired.
*
* vp must be locked and referenced.
*/
static bool
ext2fs_rmdired_p(struct vnode *vp)
{
KASSERT(vp != NULL);
KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
KASSERT(vp->v_type == VDIR);
/* XXX Is this correct? */
return (ext2fs_size(VTOI(vp)) == 0);
}
/*
* ext2fs_gro_genealogy: Analyze the genealogy of the source and target
* directories.
*/
static int
ext2fs_gro_genealogy(struct mount *mp, kauth_cred_t cred,
struct vnode *fdvp, struct vnode *tdvp,
struct vnode **intermediate_node_ret)
{
struct vnode *vp, *dvp;
ino_t dotdot_ino;
int error;
KASSERT(mp != NULL);
KASSERT(fdvp != NULL);
KASSERT(tdvp != NULL);
KASSERT(fdvp != tdvp);
KASSERT(intermediate_node_ret != NULL);
KASSERT(fdvp->v_mount == mp);
KASSERT(tdvp->v_mount == mp);
KASSERT(fdvp->v_type == VDIR);
KASSERT(tdvp->v_type == VDIR);
/*
* We need to provisionally lock tdvp to keep rmdir from
* deleting it -- or any ancestor -- at an inopportune moment.
*/
error = ext2fs_gro_lock_directory(mp, tdvp);
if (error)
return error;
vp = tdvp;
vref(vp);
for (;;) {
KASSERT(vp != NULL);
KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
KASSERT(vp->v_mount == mp);
KASSERT(vp->v_type == VDIR);
KASSERT(!ext2fs_rmdired_p(vp));
/* Did we hit the root without finding fdvp? */
if (VTOI(vp)->i_number == UFS_ROOTINO) {
vput(vp);
*intermediate_node_ret = NULL;
return 0;
}
error = ext2fs_read_dotdot(vp, cred, &dotdot_ino);
if (error) {
vput(vp);
return error;
}
/* Did we find that fdvp is an ancestor of tdvp? */
if (VTOI(fdvp)->i_number == dotdot_ino) {
/* Unlock vp, but keep it referenced. */
VOP_UNLOCK(vp);
*intermediate_node_ret = vp;
return 0;
}
/* Neither -- keep ascending the family tree. */
/*
* Unlock vp so that we can lock the parent, but keep
* vp referenced until after we have found the parent,
* so that dotdot_ino will not be recycled.
*
* XXX This guarantees that vp's inode number will not
* be recycled, but why can't dotdot_ino be recycled?
*/
VOP_UNLOCK(vp);
error = VFS_VGET(mp, dotdot_ino, &dvp);
vrele(vp);
if (error)
return error;
KASSERT(dvp != NULL);
KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
vp = dvp;
if (vp->v_type != VDIR) {
/*
* XXX Panic? Print a warning? Can this
* happen if we lose the race I suspect to
* exist above, and the `..' inode number has
* been recycled?
*/
vput(vp);
return ENOTDIR;
}
if (ext2fs_rmdired_p(vp)) {
vput(vp);
return ENOENT;
}
}
}
/*
* ext2fs_read_dotdot: Store in *ino_ret the inode number of the parent
* of the directory vp.
*/
static int
ext2fs_read_dotdot(struct vnode *vp, kauth_cred_t cred, ino_t *ino_ret)
{
struct ext2fs_dirtemplate dirbuf;
int error;
KASSERT(vp != NULL);
KASSERT(ino_ret != NULL);
KASSERT(vp->v_type == VDIR);
error = vn_rdwr(UIO_READ, vp, &dirbuf, sizeof dirbuf, (off_t)0,
UIO_SYSSPACE, IO_NODELOCKED, cred, NULL, NULL);
if (error)
return error;
if (dirbuf.dotdot_namlen != 2 ||
dirbuf.dotdot_name[0] != '.' ||
dirbuf.dotdot_name[1] != '.')
/* XXX Panic? Print warning? */
return ENOTDIR;
*ino_ret = fs2h32(dirbuf.dotdot_ino);
return 0;
}
/*
* ext2fs_rename_replace_dotdot: Change the target of the `..' entry of
* the directory vp from fdvp to tdvp.
*/
static int
ext2fs_rename_replace_dotdot(struct vnode *vp,
struct vnode *fdvp, struct vnode *tdvp,
kauth_cred_t cred)
{
struct ext2fs_dirtemplate dirbuf;
int error;
/* XXX Does it make sense to do this before the sanity checks below? */
KASSERT(0 < VTOI(fdvp)->i_e2fs_nlink);
VTOI(fdvp)->i_e2fs_nlink--;
VTOI(fdvp)->i_flag |= IN_CHANGE;
error = vn_rdwr(UIO_READ, vp, &dirbuf, sizeof dirbuf, (off_t)0,
UIO_SYSSPACE, IO_NODELOCKED, cred, NULL, NULL);
if (error)
return error;
if (dirbuf.dotdot_namlen != 2 ||
dirbuf.dotdot_name[0] != '.' ||
dirbuf.dotdot_name[1] != '.') {
ufs_dirbad(VTOI(vp), (doff_t)12, "bad `..' entry");
return 0;
}
if (fs2h32(dirbuf.dotdot_ino) != VTOI(fdvp)->i_number) {
ufs_dirbad(VTOI(vp), (doff_t)12,
"`..' does not point at parent");
return 0;
}
dirbuf.dotdot_ino = h2fs32(VTOI(tdvp)->i_number);
/* XXX WTF? Why not check error? */
(void)vn_rdwr(UIO_WRITE, vp, &dirbuf, sizeof dirbuf, (off_t)0,
UIO_SYSSPACE, (IO_NODELOCKED | IO_SYNC), cred, NULL, NULL);
return 0;
}
/*
* ext2fs_gro_lock_directory: Lock the directory vp, but fail if it has
* been rmdir'd.
*/
static int
ext2fs_gro_lock_directory(struct mount *mp, struct vnode *vp)
{
(void)mp;
KASSERT(mp != NULL);
KASSERT(vp != NULL);
KASSERT(vp->v_mount == mp);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
if (ext2fs_rmdired_p(vp)) {
VOP_UNLOCK(vp);
return ENOENT;
}
return 0;
}
static const struct genfs_rename_ops ext2fs_genfs_rename_ops = {
.gro_directory_empty_p = ext2fs_gro_directory_empty_p,
.gro_rename_check_possible = ext2fs_gro_rename_check_possible,
.gro_rename_check_permitted = ext2fs_gro_rename_check_permitted,
.gro_remove_check_possible = ext2fs_gro_remove_check_possible,
.gro_remove_check_permitted = ext2fs_gro_remove_check_permitted,
.gro_rename = ext2fs_gro_rename,
.gro_remove = ext2fs_gro_remove,
.gro_lookup = ext2fs_gro_lookup,
.gro_genealogy = ext2fs_gro_genealogy,
.gro_lock_directory = ext2fs_gro_lock_directory,
};
+4 -5
View File
@@ -1,4 +1,4 @@
/* $NetBSD: ext2fs_subr.c,v 1.27 2009/10/19 18:41:17 bouyer Exp $ */
/* $NetBSD: ext2fs_subr.c,v 1.30 2013/06/23 07:28:37 dholland Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@@ -60,7 +60,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ext2fs_subr.c,v 1.27 2009/10/19 18:41:17 bouyer Exp $");
__KERNEL_RCSID(0, "$NetBSD: ext2fs_subr.c,v 1.30 2013/06/23 07:28:37 dholland Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -89,15 +89,14 @@ ext2fs_blkatoff(struct vnode *vp, off_t offset, char **res, struct buf **bpp)
ip = VTOI(vp);
fs = ip->i_e2fs;
lbn = lblkno(fs, offset);
lbn = ext2_lblkno(fs, offset);
*bpp = NULL;
if ((error = bread(vp, lbn, fs->e2fs_bsize, NOCRED, 0, &bp)) != 0) {
brelse(bp, 0);
return (error);
}
if (res)
*res = (char *)bp->b_data + blkoff(fs, offset);
*res = (char *)bp->b_data + ext2_blkoff(fs, offset);
*bpp = bp;
return (0);
}
+47 -47
View File
@@ -1,4 +1,4 @@
/* $NetBSD: ext2fs_vfsops.c,v 1.162 2011/11/14 18:35:14 hannken Exp $ */
/* $NetBSD: ext2fs_vfsops.c,v 1.175 2013/11/23 13:35:36 christos Exp $ */
/*
* Copyright (c) 1989, 1991, 1993, 1994
@@ -60,7 +60,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ext2fs_vfsops.c,v 1.162 2011/11/14 18:35:14 hannken Exp $");
__KERNEL_RCSID(0, "$NetBSD: ext2fs_vfsops.c,v 1.175 2013/11/23 13:35:36 christos Exp $");
#if defined(_KERNEL_OPT)
#include "opt_compat_netbsd.h"
@@ -159,7 +159,6 @@ static const struct ufs_ops ext2fs_ufsops = {
.uo_itimes = ext2fs_itimes,
.uo_update = ext2fs_update,
.uo_vfree = ext2fs_vfree,
.uo_unmark_vnode = (void (*)(vnode_t *))nullop,
};
/* Fill in the inode uid/gid from ext2 halves. */
@@ -279,9 +278,7 @@ ext2fs_mountroot(void)
vfs_destroy(mp);
return (error);
}
mutex_enter(&mountlist_lock);
CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
mutex_exit(&mountlist_lock);
mountlist_append(mp);
ump = VFSTOUFS(mp);
fs = ump->um_e2fs;
memset(fs->e2fs_fsmnt, 0, sizeof(fs->e2fs_fsmnt));
@@ -390,7 +387,9 @@ ext2fs_mount(struct mount *mp, const char *path, void *data, size_t *data_len)
(mp->mnt_flag & MNT_RDONLY) == 0)
accessmode |= VWRITE;
vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
error = genfs_can_mount(devvp, accessmode, l->l_cred);
error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
KAUTH_REQ_SYSTEM_MOUNT_DEVICE, mp, devvp,
KAUTH_ARG(accessmode));
VOP_UNLOCK(devvp);
}
@@ -545,7 +544,6 @@ ext2fs_reload(struct mount *mp, kauth_cred_t cred, struct lwp *l)
*/
error = bread(devvp, SBLOCK, SBSIZE, NOCRED, 0, &bp);
if (error) {
brelse(bp, 0);
return (error);
}
newfs = (struct ext2fs *)bp->b_data;
@@ -580,11 +578,10 @@ ext2fs_reload(struct mount *mp, kauth_cred_t cred, struct lwp *l)
for (i = 0; i < fs->e2fs_ngdb; i++) {
error = bread(devvp ,
fsbtodb(fs, fs->e2fs.e2fs_first_dblock +
EXT2_FSBTODB(fs, fs->e2fs.e2fs_first_dblock +
1 /* superblock */ + i),
fs->e2fs_bsize, NOCRED, 0, &bp);
if (error) {
brelse(bp, 0);
return (error);
}
e2fs_cgload((struct ext2_gd *)bp->b_data,
@@ -608,7 +605,7 @@ loop:
/*
* Step 4: invalidate all inactive vnodes.
*/
if (vrecycle(vp, &mntvnode_lock, l)) {
if (vrecycle(vp, &mntvnode_lock)) {
mutex_enter(&mntvnode_lock);
(void)vunmark(mvp);
goto loop;
@@ -629,7 +626,7 @@ loop:
* Step 6: re-read inode data for all active vnodes.
*/
ip = VTOI(vp);
error = bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
error = bread(devvp, EXT2_FSBTODB(fs, ino_to_fsba(fs, ip->i_number)),
(int)fs->e2fs_bsize, NOCRED, 0, &bp);
if (error) {
vput(vp);
@@ -664,10 +661,8 @@ ext2fs_mountfs(struct vnode *devvp, struct mount *mp)
dev_t dev;
int error, i, ronly;
kauth_cred_t cred;
struct proc *p;
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. */
@@ -692,12 +687,10 @@ ext2fs_mountfs(struct vnode *devvp, struct mount *mp)
error = ext2fs_checksb(fs, ronly);
if (error)
goto out;
ump = malloc(sizeof(*ump), M_UFSMNT, M_WAITOK);
memset(ump, 0, sizeof(*ump));
ump = kmem_zalloc(sizeof(*ump), KM_SLEEP);
ump->um_fstype = UFS1;
ump->um_ops = &ext2fs_ufsops;
ump->um_e2fs = malloc(sizeof(struct m_ext2fs), M_UFSMNT, M_WAITOK);
memset(ump->um_e2fs, 0, sizeof(struct m_ext2fs));
ump->um_e2fs = kmem_zalloc(sizeof(struct m_ext2fs), KM_SLEEP);
e2fs_sbload((struct ext2fs *)bp->b_data, &ump->um_e2fs->e2fs);
brelse(bp, 0);
bp = NULL;
@@ -729,15 +722,15 @@ ext2fs_mountfs(struct vnode *devvp, struct mount *mp)
m_fs->e2fs_ipb = m_fs->e2fs_bsize / EXT2_DINODE_SIZE(m_fs);
m_fs->e2fs_itpg = m_fs->e2fs.e2fs_ipg / m_fs->e2fs_ipb;
m_fs->e2fs_gd = malloc(m_fs->e2fs_ngdb * m_fs->e2fs_bsize,
M_UFSMNT, M_WAITOK);
m_fs->e2fs_gd = kmem_alloc(m_fs->e2fs_ngdb * m_fs->e2fs_bsize, KM_SLEEP);
for (i = 0; i < m_fs->e2fs_ngdb; i++) {
error = bread(devvp ,
fsbtodb(m_fs, m_fs->e2fs.e2fs_first_dblock +
EXT2_FSBTODB(m_fs, m_fs->e2fs.e2fs_first_dblock +
1 /* superblock */ + i),
m_fs->e2fs_bsize, NOCRED, 0, &bp);
if (error) {
free(m_fs->e2fs_gd, M_UFSMNT);
kmem_free(m_fs->e2fs_gd,
m_fs->e2fs_ngdb * m_fs->e2fs_bsize);
goto out;
}
e2fs_cgload((struct ext2_gd *)bp->b_data,
@@ -761,22 +754,22 @@ ext2fs_mountfs(struct vnode *devvp, struct mount *mp)
ump->um_mountp = mp;
ump->um_dev = dev;
ump->um_devvp = devvp;
ump->um_nindir = NINDIR(m_fs);
ump->um_lognindir = ffs(NINDIR(m_fs)) - 1;
ump->um_nindir = EXT2_NINDIR(m_fs);
ump->um_lognindir = ffs(EXT2_NINDIR(m_fs)) - 1;
ump->um_bptrtodb = m_fs->e2fs_fsbtodb;
ump->um_seqinc = 1; /* no frags */
ump->um_maxsymlinklen = EXT2_MAXSYMLINKLEN;
ump->um_dirblksiz = m_fs->e2fs_bsize;
ump->um_maxfilesize = ((uint64_t)0x80000000 * m_fs->e2fs_bsize - 1);
devvp->v_specmountpoint = mp;
spec_node_setmountedfs(devvp, mp);
return (0);
out:
KASSERT(bp != NULL);
brelse(bp, 0);
if (bp != NULL)
brelse(bp, 0);
if (ump) {
free(ump->um_e2fs, M_UFSMNT);
free(ump, M_UFSMNT);
kmem_free(ump->um_e2fs, sizeof(struct m_ext2fs));
kmem_free(ump, sizeof(*ump));
mp->mnt_data = NULL;
}
return (error);
@@ -806,14 +799,14 @@ ext2fs_unmount(struct mount *mp, int mntflags)
(void) ext2fs_sbupdate(ump, MNT_WAIT);
}
if (ump->um_devvp->v_type != VBAD)
ump->um_devvp->v_specmountpoint = NULL;
spec_node_setmountedfs(ump->um_devvp, NULL);
vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY);
error = VOP_CLOSE(ump->um_devvp, fs->e2fs_ronly ? FREAD : FREAD|FWRITE,
NOCRED);
vput(ump->um_devvp);
free(fs->e2fs_gd, M_UFSMNT);
free(fs, M_UFSMNT);
free(ump, M_UFSMNT);
kmem_free(fs->e2fs_gd, fs->e2fs_ngdb * fs->e2fs_bsize);
kmem_free(fs, sizeof(*fs));
kmem_free(ump, sizeof(*ump));
mp->mnt_data = NULL;
mp->mnt_flag &= ~MNT_LOCAL;
return (error);
@@ -1051,7 +1044,7 @@ retry:
mutex_exit(&ufs_hashlock);
/* Read in the disk contents for the inode, copy into the inode. */
error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
error = bread(ump->um_devvp, EXT2_FSBTODB(fs, ino_to_fsba(fs, ino)),
(int)fs->e2fs_bsize, NOCRED, 0, &bp);
if (error) {
@@ -1063,7 +1056,6 @@ retry:
*/
vput(vp);
brelse(bp, 0);
*vpp = NULL;
return (error);
}
@@ -1075,8 +1067,9 @@ retry:
/* If the inode was deleted, reset all fields */
if (ip->i_e2fs_dtime != 0) {
ip->i_e2fs_mode = ip->i_e2fs_nblock = 0;
ip->i_e2fs_mode = 0;
(void)ext2fs_setsize(ip, 0);
(void)ext2fs_setnblock(ip, 0);
memset(ip->i_e2fs_blocks, 0, sizeof(ip->i_e2fs_blocks));
}
@@ -1208,7 +1201,7 @@ ext2fs_cgupdate(struct ufsmount *mp, int waitfor)
allerror = ext2fs_sbupdate(mp, waitfor);
for (i = 0; i < fs->e2fs_ngdb; i++) {
bp = getblk(mp->um_devvp, fsbtodb(fs,
bp = getblk(mp->um_devvp, EXT2_FSBTODB(fs,
fs->e2fs.e2fs_first_dblock +
1 /* superblock */ + i), fs->e2fs_bsize, 0, 0);
e2fs_cgsave(&fs->e2fs_gd[
@@ -1228,38 +1221,45 @@ ext2fs_cgupdate(struct ufsmount *mp, int waitfor)
static int
ext2fs_checksb(struct ext2fs *fs, int ronly)
{
uint32_t u32;
if (fs2h16(fs->e2fs_magic) != E2FS_MAGIC) {
return (EINVAL); /* XXX needs translation */
}
if (fs2h32(fs->e2fs_rev) > E2FS_REV1) {
#ifdef DIAGNOSTIC
printf("Ext2 fs: unsupported revision number: %x\n",
printf("ext2fs: unsupported revision number: %x\n",
fs2h32(fs->e2fs_rev));
#endif
return (EINVAL); /* XXX needs translation */
}
if (fs2h32(fs->e2fs_log_bsize) > 2) { /* block size = 1024|2048|4096 */
#ifdef DIAGNOSTIC
printf("Ext2 fs: bad block size: %d "
printf("ext2fs: bad block size: %d "
"(expected <= 2 for ext2 fs)\n",
fs2h32(fs->e2fs_log_bsize));
#endif
return (EINVAL); /* XXX needs translation */
}
if (fs2h32(fs->e2fs_rev) > E2FS_REV0) {
char buf[256];
if (fs2h32(fs->e2fs_first_ino) != EXT2_FIRSTINO) {
printf("Ext2 fs: unsupported first inode position\n");
printf("ext2fs: unsupported first inode position\n");
return (EINVAL); /* XXX needs translation */
}
if (fs2h32(fs->e2fs_features_incompat) &
~EXT2F_INCOMPAT_SUPP) {
printf("Ext2 fs: unsupported optional feature\n");
return (EINVAL); /* XXX needs translation */
u32 = fs2h32(fs->e2fs_features_incompat) & ~EXT2F_INCOMPAT_SUPP;
if (u32) {
snprintb(buf, sizeof(buf), EXT2F_INCOMPAT_BITS, u32);
printf("ext2fs: unsupported incompat features: %s\n",
buf);
return EINVAL; /* XXX needs translation */
}
if (!ronly && fs2h32(fs->e2fs_features_rocompat) &
~EXT2F_ROCOMPAT_SUPP) {
return (EROFS); /* XXX needs translation */
u32 = fs2h32(fs->e2fs_features_rocompat) & ~EXT2F_ROCOMPAT_SUPP;
if (!ronly && u32) {
snprintb(buf, sizeof(buf), EXT2F_ROCOMPAT_BITS, u32);
printf("ext2fs: unsupported ro-incompat features: %s\n",
buf);
return EROFS; /* XXX needs translation */
}
}
return (0);
+66 -455
View File
@@ -1,4 +1,4 @@
/* $NetBSD: ext2fs_vnops.c,v 1.101 2011/11/18 21:18:51 christos Exp $ */
/* $NetBSD: ext2fs_vnops.c,v 1.107 2013/03/18 19:35:47 plunky Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@@ -65,7 +65,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ext2fs_vnops.c,v 1.101 2011/11/18 21:18:51 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: ext2fs_vnops.c,v 1.107 2013/03/18 19:35:47 plunky Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -253,8 +253,9 @@ ext2fs_check_permitted(struct vnode *vp, struct inode *ip, mode_t mode,
kauth_cred_t cred)
{
return genfs_can_access(vp->v_type, ip->i_e2fs_mode & ALLPERMS,
ip->i_uid, ip->i_gid, mode, cred);
return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode, vp->v_type,
ip->i_e2fs_mode & ALLPERMS), vp, NULL, genfs_can_access(vp->v_type,
ip->i_e2fs_mode & ALLPERMS, ip->i_uid, ip->i_gid, mode, cred));
}
int
@@ -325,7 +326,7 @@ ext2fs_getattr(void *v)
vap->va_blocksize = MAXBSIZE;
else
vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
vap->va_bytes = dbtob((u_quad_t)ip->i_e2fs_nblock);
vap->va_bytes = dbtob(ext2fs_nblock(ip));
vap->va_type = vp->v_type;
vap->va_filerev = ip->i_modrev;
return (0);
@@ -348,6 +349,8 @@ ext2fs_setattr(void *v)
kauth_cred_t cred = ap->a_cred;
struct lwp *l = curlwp;
int error;
kauth_action_t action = KAUTH_VNODE_WRITE_FLAGS;
bool changing_sysflags = false;
/*
* Check for unsettable attributes.
@@ -361,24 +364,38 @@ ext2fs_setattr(void *v)
if (vap->va_flags != VNOVAL) {
if (vp->v_mount->mnt_flag & MNT_RDONLY)
return (EROFS);
if (kauth_cred_geteuid(cred) != ip->i_uid &&
(error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
NULL)))
return (error);
/*
* Check if we're allowed to change the flags.
* If EXT2FS_SYSTEM_FLAGS is set, then the flags are treated
* as system flags, otherwise they're considered to be user
* flags.
*/
#ifdef EXT2FS_SYSTEM_FLAGS
if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
NULL) == 0) {
if ((ip->i_e2fs_flags &
(EXT2_APPEND | EXT2_IMMUTABLE)) &&
kauth_authorize_system(l->l_cred,
KAUTH_SYSTEM_CHSYSFLAGS, 0, NULL, NULL, NULL))
return (EPERM);
ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE);
ip->i_e2fs_flags |=
(vap->va_flags & SF_APPEND) ? EXT2_APPEND : 0 |
(vap->va_flags & SF_IMMUTABLE) ? EXT2_IMMUTABLE : 0;
} else
return (EPERM);
/* Indicate we're changing system flags if we are. */
if ((vap->va_flags & SF_APPEND) ||
(vap->va_flags & SF_IMMUTABLE)) {
action |= KAUTH_VNODE_WRITE_SYSFLAGS;
changing_sysflags = true;
}
/* Indicate the node has system flags if it does. */
if (ip->i_e2fs_flags & (EXT2_APPEND | EXT2_IMMUTABLE)) {
action |= KAUTH_VNODE_HAS_SYSFLAGS;
}
#endif /* EXT2FS_SYSTEM_FLAGS */
error = kauth_authorize_vnode(cred, action, vp, NULL,
genfs_can_chflags(cred, vp->v_type, ip->i_uid,
changing_sysflags));
if (error)
return (error);
#ifdef EXT2FS_SYSTEM_FLAGS
ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE);
ip->i_e2fs_flags |=
(vap->va_flags & SF_APPEND) ? EXT2_APPEND : 0 |
(vap->va_flags & SF_IMMUTABLE) ? EXT2_IMMUTABLE : 0;
#else
ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE);
ip->i_e2fs_flags |=
@@ -425,7 +442,9 @@ ext2fs_setattr(void *v)
if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
if (vp->v_mount->mnt_flag & MNT_RDONLY)
return (EROFS);
error = genfs_can_chtimes(vp, vap->va_vaflags, ip->i_uid, cred);
error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
NULL, genfs_can_chtimes(vp, vap->va_vaflags, ip->i_uid,
cred));
if (error)
return (error);
if (vap->va_atime.tv_sec != VNOVAL)
@@ -461,7 +480,9 @@ ext2fs_chmod(struct vnode *vp, int mode, kauth_cred_t cred, struct lwp *l)
struct inode *ip = VTOI(vp);
int error;
error = genfs_can_chmod(vp, cred, ip->i_uid, ip->i_gid, mode);
error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp,
NULL, genfs_can_chmod(vp->v_type, cred, ip->i_uid, ip->i_gid,
mode));
if (error)
return (error);
@@ -489,7 +510,8 @@ ext2fs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred,
if (gid == (gid_t)VNOVAL)
gid = ip->i_gid;
error = genfs_can_chown(vp, cred, ip->i_uid, ip->i_gid, uid, gid);
error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP, vp,
NULL, genfs_can_chown(cred, ip->i_uid, ip->i_gid, uid, gid));
if (error)
return (error);
@@ -509,11 +531,13 @@ ext2fs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred,
ext2fs_set_inode_guid(ip);
ip->i_flag |= IN_CHANGE;
}
if (ouid != uid && kauth_authorize_generic(cred,
KAUTH_GENERIC_ISSUSER, NULL) != 0)
if (ouid != uid && (ip->i_e2fs_mode & ISUID) &&
kauth_authorize_vnode(cred, KAUTH_VNODE_RETAIN_SUID,
vp, NULL, EPERM) != 0)
ip->i_e2fs_mode &= ~ISUID;
if (ogid != gid && kauth_authorize_generic(cred,
KAUTH_GENERIC_ISSUSER, NULL) != 0)
if (ogid != gid && (ip->i_e2fs_mode & ISGID) &&
kauth_authorize_vnode(cred, KAUTH_VNODE_RETAIN_SGID,
vp, NULL, EPERM) != 0)
ip->i_e2fs_mode &= ~ISGID;
return (0);
}
@@ -619,424 +643,6 @@ out2:
return (error);
}
/*
* Rename system call.
* rename("foo", "bar");
* is essentially
* unlink("bar");
* link("foo", "bar");
* unlink("foo");
* but ``atomically''. Can't do full commit without saving state in the
* inode on disk which isn't feasible at this time. Best we can do is
* always guarantee the target exists.
*
* Basic algorithm is:
*
* 1) Bump link count on source while we're linking it to the
* target. This also ensure the inode won't be deleted out
* from underneath us while we work (it may be truncated by
* a concurrent `trunc' or `open' for creation).
* 2) Link source to destination. If destination already exists,
* delete it first.
* 3) Unlink source reference to inode if still around. If a
* directory was moved and the parent of the destination
* is different from the source, patch the ".." entry in the
* directory.
*/
int
ext2fs_rename(void *v)
{
struct vop_rename_args /* {
struct vnode *a_fdvp;
struct vnode *a_fvp;
struct componentname *a_fcnp;
struct vnode *a_tdvp;
struct vnode *a_tvp;
struct componentname *a_tcnp;
} */ *ap = v;
struct vnode *tvp = ap->a_tvp;
struct vnode *tdvp = ap->a_tdvp;
struct vnode *fvp = ap->a_fvp;
struct vnode *fdvp = ap->a_fdvp;
struct componentname *tcnp = ap->a_tcnp;
struct componentname *fcnp = ap->a_fcnp;
struct inode *ip, *xp, *dp;
struct ext2fs_dirtemplate dirbuf;
int doingdirectory = 0, oldparent = 0, newparent = 0;
int error = 0;
u_char namlen;
/*
* Check for cross-device rename.
*/
if ((fvp->v_mount != tdvp->v_mount) ||
(tvp && (fvp->v_mount != tvp->v_mount))) {
error = EXDEV;
abortit:
VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
if (tdvp == tvp)
vrele(tdvp);
else
vput(tdvp);
if (tvp)
vput(tvp);
VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
vrele(fdvp);
vrele(fvp);
return (error);
}
/*
* Check if just deleting a link name.
*/
if (tvp && ((VTOI(tvp)->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) ||
(VTOI(tdvp)->i_e2fs_flags & EXT2_APPEND))) {
error = EPERM;
goto abortit;
}
if (fvp == tvp) {
if (fvp->v_type == VDIR) {
error = EINVAL;
goto abortit;
}
/* Release destination completely. */
VOP_ABORTOP(tdvp, tcnp);
vput(tdvp);
vput(tvp);
/* Delete source. */
vrele(fvp);
fcnp->cn_flags &= ~(MODMASK);
fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
fcnp->cn_nameiop = DELETE;
vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY);
if ((error = relookup(fdvp, &fvp, fcnp, 0))) {
vput(fdvp);
return (error);
}
return (VOP_REMOVE(fdvp, fvp, fcnp));
}
if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0)
goto abortit;
dp = VTOI(fdvp);
ip = VTOI(fvp);
if ((nlink_t) ip->i_e2fs_nlink >= LINK_MAX) {
VOP_UNLOCK(fvp);
error = EMLINK;
goto abortit;
}
if ((ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) ||
(dp->i_e2fs_flags & EXT2_APPEND)) {
VOP_UNLOCK(fvp);
error = EPERM;
goto abortit;
}
if ((ip->i_e2fs_mode & IFMT) == IFDIR) {
error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred);
if (!error && tvp)
error = VOP_ACCESS(tvp, VWRITE, tcnp->cn_cred);
if (error) {
VOP_UNLOCK(fvp);
error = EACCES;
goto abortit;
}
/*
* Avoid ".", "..", and aliases of "." for obvious reasons.
*/
if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
dp == ip ||
(fcnp->cn_flags & ISDOTDOT) ||
(tcnp->cn_flags & ISDOTDOT) ||
(ip->i_flag & IN_RENAME)) {
VOP_UNLOCK(fvp);
error = EINVAL;
goto abortit;
}
ip->i_flag |= IN_RENAME;
oldparent = dp->i_number;
doingdirectory = 1;
}
VN_KNOTE(fdvp, NOTE_WRITE); /* XXXLUKEM/XXX: right place? */
/*
* When the target exists, both the directory
* and target vnodes are returned locked.
*/
dp = VTOI(tdvp);
xp = NULL;
if (tvp)
xp = VTOI(tvp);
/*
* 1) Bump link count while we're moving stuff
* around. If we crash somewhere before
* completing our work, the link count
* may be wrong, but correctable.
*/
ip->i_e2fs_nlink++;
ip->i_flag |= IN_CHANGE;
if ((error = ext2fs_update(fvp, NULL, NULL, UPDATE_WAIT)) != 0) {
VOP_UNLOCK(fvp);
goto bad;
}
/*
* If ".." must be changed (ie the directory gets a new
* parent) then the source directory must not be in the
* directory hierarchy above the target, as this would
* orphan everything below the source directory. Also
* the user must have write permission in the source so
* as to be able to change "..". We must repeat the call
* to namei, as the parent directory is unlocked by the
* call to checkpath().
*/
error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred);
VOP_UNLOCK(fvp);
if (oldparent != dp->i_number)
newparent = dp->i_number;
if (doingdirectory && newparent) {
if (error) /* write access check above */
goto bad;
if (xp != NULL)
vput(tvp);
vref(tdvp); /* compensate for the ref checkpath loses */
error = ext2fs_checkpath(ip, dp, tcnp->cn_cred);
if (error != 0) {
vrele(tdvp);
goto out;
}
vn_lock(tdvp, LK_EXCLUSIVE | LK_RETRY);
if ((error = relookup(tdvp, &tvp, tcnp, 0)) != 0) {
vput(tdvp);
goto out;
}
dp = VTOI(tdvp);
xp = NULL;
if (tvp)
xp = VTOI(tvp);
}
/*
* 2) If target doesn't exist, link the target
* to the source and unlink the source.
* Otherwise, rewrite the target directory
* entry to reference the source inode and
* expunge the original entry's existence.
*/
if (xp == NULL) {
if (dp->i_dev != ip->i_dev)
panic("rename: EXDEV");
/*
* Account for ".." in new directory.
* When source and destination have the same
* parent we don't fool with the link count.
*/
if (doingdirectory && newparent) {
if ((nlink_t)dp->i_e2fs_nlink >= LINK_MAX) {
error = EMLINK;
goto bad;
}
dp->i_e2fs_nlink++;
dp->i_flag |= IN_CHANGE;
if ((error = ext2fs_update(tdvp, NULL, NULL,
UPDATE_WAIT)) != 0)
goto bad;
}
error = ext2fs_direnter(ip, tdvp, &VTOI(tdvp)->i_crap, tcnp);
if (error != 0) {
if (doingdirectory && newparent) {
dp->i_e2fs_nlink--;
dp->i_flag |= IN_CHANGE;
(void)ext2fs_update(tdvp, NULL, NULL,
UPDATE_WAIT);
}
goto bad;
}
VN_KNOTE(tdvp, NOTE_WRITE);
vput(tdvp);
} else {
if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
panic("rename: EXDEV");
/*
* Short circuit rename(foo, foo).
*/
if (xp->i_number == ip->i_number)
panic("rename: same file");
/*
* If the parent directory is "sticky", then the user must
* own the parent directory, or the destination of the rename,
* otherwise the destination may not be changed (except by
* root). This implements append-only directories.
*/
if ((dp->i_e2fs_mode & S_ISTXT) &&
kauth_authorize_generic(tcnp->cn_cred,
KAUTH_GENERIC_ISSUSER, NULL) != 0 &&
kauth_cred_geteuid(tcnp->cn_cred) != dp->i_uid &&
xp->i_uid != kauth_cred_geteuid(tcnp->cn_cred)) {
error = EPERM;
goto bad;
}
/*
* Target must be empty if a directory and have no links
* to it. Also, ensure source and target are compatible
* (both directories, or both not directories).
*/
if ((xp->i_e2fs_mode & IFMT) == IFDIR) {
if (!ext2fs_dirempty(xp, dp->i_number, tcnp->cn_cred) ||
xp->i_e2fs_nlink > 2) {
error = ENOTEMPTY;
goto bad;
}
if (!doingdirectory) {
error = ENOTDIR;
goto bad;
}
cache_purge(tdvp);
} else if (doingdirectory) {
error = EISDIR;
goto bad;
}
error = ext2fs_dirrewrite(dp, &dp->i_crap, ip, tcnp);
if (error != 0)
goto bad;
/*
* If the target directory is in the same
* directory as the source directory,
* decrement the link count on the parent
* of the target directory.
*/
if (doingdirectory && !newparent) {
dp->i_e2fs_nlink--;
dp->i_flag |= IN_CHANGE;
}
/*
* Adjust the link count of the target to
* reflect the dirrewrite above. If this is
* a directory it is empty and there are
* no links to it, so we can squash the inode and
* any space associated with it. We disallowed
* renaming over top of a directory with links to
* it above, as the remaining link would point to
* a directory without "." or ".." entries.
*/
xp->i_e2fs_nlink--;
if (doingdirectory) {
if (--xp->i_e2fs_nlink != 0)
panic("rename: linked directory");
error = ext2fs_truncate(tvp, (off_t)0, IO_SYNC,
tcnp->cn_cred);
}
xp->i_flag |= IN_CHANGE;
VN_KNOTE(tdvp, NOTE_WRITE);
vput(tdvp);
VN_KNOTE(tvp, NOTE_DELETE);
vput(tvp);
xp = NULL;
}
/*
* 3) Unlink the source.
*/
fcnp->cn_flags &= ~(MODMASK);
fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY);
if ((error = relookup(fdvp, &fvp, fcnp, 0))) {
vput(fdvp);
vrele(ap->a_fvp);
return (error);
}
if (fvp != NULL) {
xp = VTOI(fvp);
dp = VTOI(fdvp);
} else {
/*
* From name has disappeared.
*/
if (doingdirectory)
panic("ext2fs_rename: lost dir entry");
vrele(ap->a_fvp);
return (0);
}
/*
* Ensure that the directory entry still exists and has not
* changed while the new name has been entered. If the source is
* a file then the entry may have been unlinked or renamed. In
* either case there is no further work to be done. If the source
* is a directory then it cannot have been rmdir'ed; its link
* count of three would cause a rmdir to fail with ENOTEMPTY.
* The IRENAME flag ensures that it cannot be moved by another
* rename.
*/
if (xp != ip) {
if (doingdirectory)
panic("ext2fs_rename: lost dir entry");
} else {
/*
* If the source is a directory with a
* new parent, the link count of the old
* parent directory must be decremented
* and ".." set to point to the new parent.
*/
if (doingdirectory && newparent) {
KASSERT(dp != NULL);
dp->i_e2fs_nlink--;
dp->i_flag |= IN_CHANGE;
error = vn_rdwr(UIO_READ, fvp, (void *)&dirbuf,
sizeof (struct ext2fs_dirtemplate), (off_t)0,
UIO_SYSSPACE, IO_NODELOCKED,
tcnp->cn_cred, (size_t *)0, NULL);
if (error == 0) {
namlen = dirbuf.dotdot_namlen;
if (namlen != 2 ||
dirbuf.dotdot_name[0] != '.' ||
dirbuf.dotdot_name[1] != '.') {
ufs_dirbad(xp, (doff_t)12,
"ext2fs_rename: mangled dir");
} else {
dirbuf.dotdot_ino = h2fs32(newparent);
(void) vn_rdwr(UIO_WRITE, fvp,
(void *)&dirbuf,
sizeof (struct dirtemplate),
(off_t)0, UIO_SYSSPACE,
IO_NODELOCKED|IO_SYNC,
tcnp->cn_cred, (size_t *)0,
NULL);
cache_purge(fdvp);
}
}
}
error = ext2fs_dirremove(fdvp, &VTOI(fdvp)->i_crap, fcnp);
if (!error) {
xp->i_e2fs_nlink--;
xp->i_flag |= IN_CHANGE;
}
xp->i_flag &= ~IN_RENAME;
}
VN_KNOTE(fvp, NOTE_RENAME);
if (dp)
vput(fdvp);
if (xp)
vput(fvp);
vrele(ap->a_fvp);
return (error);
bad:
if (xp)
vput(ITOV(xp));
vput(ITOV(dp));
out:
if (doingdirectory)
ip->i_flag &= ~IN_RENAME;
if (vn_lock(fvp, LK_EXCLUSIVE) == 0) {
ip->i_e2fs_nlink--;
ip->i_flag |= IN_CHANGE;
vput(fvp);
} else
vrele(fvp);
vrele(fdvp);
return (error);
}
/*
* Mkdir system call
*/
@@ -1316,7 +922,7 @@ ext2fs_readlink(void *v)
isize = ext2fs_size(ip);
if (isize < ump->um_maxsymlinklen ||
(ump->um_maxsymlinklen == 0 && ip->i_e2fs_nblock == 0)) {
(ump->um_maxsymlinklen == 0 && ext2fs_nblock(ip) == 0)) {
uiomove((char *)ip->i_din.e2fs_din->e2di_shortlink, isize, ap->a_uio);
return (0);
}
@@ -1361,7 +967,7 @@ ext2fs_fsync(void *v)
if (vp->v_type == VBLK)
error = spec_fsync(v);
else
error = vflushbuf(vp, wait);
error = vflushbuf(vp, ap->a_flags);
if (error == 0 && (ap->a_flags & FSYNC_DATAONLY) == 0)
error = ext2fs_update(vp, NULL, NULL, wait ? UPDATE_WAIT : 0);
@@ -1405,7 +1011,7 @@ ext2fs_vinit(struct mount *mntp, int (**specops)(void *),
case VREG:
break;
}
if (ip->i_number == ROOTINO)
if (ip->i_number == UFS_ROOTINO)
vp->v_vflag |= VV_ROOT;
/*
* Initialize modrev times
@@ -1426,7 +1032,7 @@ ext2fs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
{
struct inode *ip, *pdir;
struct vnode *tvp;
int error, ismember = 0;
int error;
struct ufs_lookup_results *ulr;
pdir = VTOI(dvp);
@@ -1459,10 +1065,15 @@ ext2fs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
ip->i_e2fs_mode = mode;
tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */
ip->i_e2fs_nlink = 1;
if ((ip->i_e2fs_mode & ISGID) && (kauth_cred_ismember_gid(cnp->cn_cred,
ip->i_gid, &ismember) != 0 || !ismember) &&
kauth_authorize_generic(cnp->cn_cred, KAUTH_GENERIC_ISSUSER, NULL))
ip->i_e2fs_mode &= ~ISGID;
/* Authorize setting SGID if needed. */
if (ip->i_e2fs_mode & ISGID) {
error = kauth_authorize_vnode(cnp->cn_cred, KAUTH_VNODE_WRITE_SECURITY,
tvp, NULL, genfs_can_chmod(tvp->v_type, cnp->cn_cred, ip->i_uid,
ip->i_gid, mode));
if (error)
ip->i_e2fs_mode &= ~ISGID;
}
/*
* Make sure inode goes to disk before directory entry.
+302 -108
View File
@@ -1,4 +1,4 @@
/* $NetBSD: ffs_alloc.c,v 1.130 2011/11/28 08:05:07 tls Exp $ */
/* $NetBSD: ffs_alloc.c,v 1.145 2013/11/12 03:29:22 dholland Exp $ */
/*-
* Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -70,7 +70,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ffs_alloc.c,v 1.130 2011/11/28 08:05:07 tls Exp $");
__KERNEL_RCSID(0, "$NetBSD: ffs_alloc.c,v 1.145 2013/11/12 03:29:22 dholland Exp $");
#if defined(_KERNEL_OPT)
#include "opt_ffs.h"
@@ -133,8 +133,8 @@ static int
ffs_check_bad_allocation(const char *func, struct fs *fs, daddr_t bno,
long size, dev_t dev, ino_t inum)
{
if ((u_int)size > fs->fs_bsize || fragoff(fs, size) != 0 ||
fragnum(fs, bno) + numfrags(fs, size) > fs->fs_frag) {
if ((u_int)size > fs->fs_bsize || ffs_fragoff(fs, size) != 0 ||
ffs_fragnum(fs, bno) + ffs_numfrags(fs, size) > fs->fs_frag) {
printf("dev = 0x%llx, bno = %" PRId64 " bsize = %d, "
"size = %ld, fs = %s\n",
(long long)dev, bno, fs->fs_bsize, size, fs->fs_fsmnt);
@@ -205,19 +205,19 @@ ffs_alloc(struct inode *ip, daddr_t lbn, daddr_t bpref, int size, int flags,
*/
if (ITOV(ip)->v_type == VREG &&
lblktosize(fs, (voff_t)lbn) < round_page(ITOV(ip)->v_size)) {
ffs_lblktosize(fs, (voff_t)lbn) < round_page(ITOV(ip)->v_size)) {
struct vm_page *pg;
struct vnode *vp = ITOV(ip);
struct uvm_object *uobj = &vp->v_uobj;
voff_t off = trunc_page(lblktosize(fs, lbn));
voff_t endoff = round_page(lblktosize(fs, lbn) + size);
voff_t off = trunc_page(ffs_lblktosize(fs, lbn));
voff_t endoff = round_page(ffs_lblktosize(fs, lbn) + size);
mutex_enter(uobj->vmobjlock);
while (off < endoff) {
pg = uvm_pagelookup(uobj, off);
KASSERT((pg == NULL && (vp->v_vflag & VV_MAPPED) == 0 &&
(size & PAGE_MASK) == 0 &&
blkoff(fs, size) == 0) ||
ffs_blkoff(fs, size) == 0) ||
(pg != NULL && pg->owner == curproc->p_pid &&
pg->lowner == curlwp->l_lid));
off += PAGE_SIZE;
@@ -228,7 +228,7 @@ ffs_alloc(struct inode *ip, daddr_t lbn, daddr_t bpref, int size, int flags,
*bnp = 0;
#ifdef DIAGNOSTIC
if ((u_int)size > fs->fs_bsize || fragoff(fs, size) != 0) {
if ((u_int)size > fs->fs_bsize || ffs_fragoff(fs, size) != 0) {
printf("dev = 0x%llx, bsize = %d, size = %d, fs = %s\n",
(unsigned long long)ip->i_dev, fs->fs_bsize, size,
fs->fs_fsmnt);
@@ -332,8 +332,8 @@ ffs_realloccg(struct inode *ip, daddr_t lbprev, daddr_t bpref, int osize,
if (ITOV(ip)->v_type == VREG) {
struct vm_page *pg;
struct uvm_object *uobj = &ITOV(ip)->v_uobj;
voff_t off = trunc_page(lblktosize(fs, lbprev));
voff_t endoff = round_page(lblktosize(fs, lbprev) + osize);
voff_t off = trunc_page(ffs_lblktosize(fs, lbprev));
voff_t endoff = round_page(ffs_lblktosize(fs, lbprev) + osize);
mutex_enter(uobj->vmobjlock);
while (off < endoff) {
@@ -347,8 +347,8 @@ ffs_realloccg(struct inode *ip, daddr_t lbprev, daddr_t bpref, int osize,
#endif
#ifdef DIAGNOSTIC
if ((u_int)osize > fs->fs_bsize || fragoff(fs, osize) != 0 ||
(u_int)nsize > fs->fs_bsize || fragoff(fs, nsize) != 0) {
if ((u_int)osize > fs->fs_bsize || ffs_fragoff(fs, osize) != 0 ||
(u_int)nsize > fs->fs_bsize || ffs_fragoff(fs, nsize) != 0) {
printf(
"dev = 0x%llx, bsize = %d, osize = %d, nsize = %d, fs = %s\n",
(unsigned long long)ip->i_dev, fs->fs_bsize, osize, nsize,
@@ -382,7 +382,6 @@ ffs_realloccg(struct inode *ip, daddr_t lbprev, daddr_t bpref, int osize,
*/
if (bpp != NULL &&
(error = bread(ITOV(ip), lbprev, osize, NOCRED, 0, &bp)) != 0) {
brelse(bp, 0);
return (error);
}
#if defined(QUOTA) || defined(QUOTA2)
@@ -403,7 +402,7 @@ ffs_realloccg(struct inode *ip, daddr_t lbprev, daddr_t bpref, int osize,
ip->i_flag |= IN_CHANGE | IN_UPDATE;
if (bpp != NULL) {
if (bp->b_blkno != fsbtodb(fs, bno))
if (bp->b_blkno != FFS_FSBTODB(fs, bno))
panic("bad blockno");
allocbuf(bp, nsize, 1);
memset((char *)bp->b_data + osize, 0, nsize - osize);
@@ -481,7 +480,7 @@ ffs_realloccg(struct inode *ip, daddr_t lbprev, daddr_t bpref, int osize,
if ((ip->i_ump->um_mountp->mnt_wapbl) &&
(ITOV(ip)->v_type != VREG)) {
UFS_WAPBL_REGISTER_DEALLOCATION(
ip->i_ump->um_mountp, fsbtodb(fs, bprev),
ip->i_ump->um_mountp, FFS_FSBTODB(fs, bprev),
osize);
} else {
ffs_blkfree(fs, ip->i_devvp, bprev, (long)osize,
@@ -492,17 +491,17 @@ ffs_realloccg(struct inode *ip, daddr_t lbprev, daddr_t bpref, int osize,
(ITOV(ip)->v_type != VREG)) {
UFS_WAPBL_REGISTER_DEALLOCATION(
ip->i_ump->um_mountp,
fsbtodb(fs, (bno + numfrags(fs, nsize))),
FFS_FSBTODB(fs, (bno + ffs_numfrags(fs, nsize))),
request - nsize);
} else
ffs_blkfree(fs, ip->i_devvp,
bno + numfrags(fs, nsize),
bno + ffs_numfrags(fs, nsize),
(long)(request - nsize), ip->i_number);
}
DIP_ADD(ip, blocks, btodb(nsize - osize));
ip->i_flag |= IN_CHANGE | IN_UPDATE;
if (bpp != NULL) {
bp->b_blkno = fsbtodb(fs, bno);
bp->b_blkno = FFS_FSBTODB(fs, bno);
allocbuf(bp, nsize, 1);
memset((char *)bp->b_data + osize, 0, (u_int)nsize - osize);
mutex_enter(bp->b_objlock);
@@ -628,7 +627,7 @@ ffs_valloc(struct vnode *pvp, int mode, kauth_cred_t cred,
printf("ino %llu ipref %llu\n", (unsigned long long)ino,
(unsigned long long)ipref);
#if 0
error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
error = bread(ump->um_devvp, FFS_FSBTODB(fs, ino_to_fsba(fs, ino)),
(int)fs->fs_bsize, NOCRED, 0, &bp);
#endif
@@ -636,8 +635,8 @@ ffs_valloc(struct vnode *pvp, int mode, kauth_cred_t cred,
panic("ffs_valloc: dup alloc");
}
if (DIP(ip, blocks)) { /* XXX */
printf("free inode %s/%llu had %" PRId64 " blocks\n",
fs->fs_fsmnt, (unsigned long long)ino, DIP(ip, blocks));
printf("free inode %llu on %s had %" PRId64 " blocks\n",
(unsigned long long)ino, fs->fs_fsmnt, DIP(ip, blocks));
DIP_ASSIGN(ip, blocks, 0);
}
ip->i_flag &= ~IN_SPACECOUNTED;
@@ -721,14 +720,17 @@ ffs_dirpref(struct inode *pip)
/*
* Count various limits which used for
* optimal allocation of a directory inode.
* Try cylinder groups with >75% avgifree and avgbfree.
* Avoid cylinder groups with no free blocks or inodes as that
* triggers an I/O-expensive cylinder group scan.
*/
maxndir = min(avgndir + fs->fs_ipg / 16, fs->fs_ipg);
minifree = avgifree - fs->fs_ipg / 4;
if (minifree < 0)
minifree = 0;
minbfree = avgbfree - fragstoblks(fs, fs->fs_fpg) / 4;
if (minbfree < 0)
minbfree = 0;
minifree = avgifree - avgifree / 4;
if (minifree < 1)
minifree = 1;
minbfree = avgbfree - avgbfree / 4;
if (minbfree < 1)
minbfree = 1;
cgsize = (int64_t)fs->fs_fsize * fs->fs_fpg;
dirsize = (int64_t)fs->fs_avgfilesize * fs->fs_avgfpdir;
if (avgndir != 0) {
@@ -737,7 +739,7 @@ ffs_dirpref(struct inode *pip)
dirsize = curdsz;
}
if (cgsize < dirsize * 255)
maxcontigdirs = cgsize / dirsize;
maxcontigdirs = (avgbfree * fs->fs_bsize) / dirsize;
else
maxcontigdirs = 255;
if (fs->fs_avgfpdir > 0)
@@ -832,11 +834,11 @@ ffs_blkpref_ufs1(struct inode *ip, daddr_t lbn, int indx, int flags,
if (flags & B_METAONLY)
return ip->i_ffs_first_indir_blk;
else
return ip->i_ffs_first_data_blk + blkstofrags(fs, lbn);
return ip->i_ffs_first_data_blk + ffs_blkstofrags(fs, lbn);
}
if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) {
if (lbn < NDADDR + NINDIR(fs)) {
if (lbn < UFS_NDADDR + FFS_NINDIR(fs)) {
cg = ino_to_cg(fs, ip->i_number);
return (cgbase(fs, cg) + fs->fs_frag);
}
@@ -896,11 +898,11 @@ ffs_blkpref_ufs2(struct inode *ip, daddr_t lbn, int indx, int flags,
if (flags & B_METAONLY)
return ip->i_ffs_first_indir_blk;
else
return ip->i_ffs_first_data_blk + blkstofrags(fs, lbn);
return ip->i_ffs_first_data_blk + ffs_blkstofrags(fs, lbn);
}
if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) {
if (lbn < NDADDR + NINDIR(fs)) {
if (lbn < UFS_NDADDR + FFS_NINDIR(fs)) {
cg = ino_to_cg(fs, ip->i_number);
return (cgbase(fs, cg) + fs->fs_frag);
}
@@ -1019,16 +1021,16 @@ ffs_fragextend(struct inode *ip, int cg, daddr_t bprev, int osize, int nsize)
KASSERT(mutex_owned(&ump->um_lock));
if (fs->fs_cs(fs, cg).cs_nffree < numfrags(fs, nsize - osize))
if (fs->fs_cs(fs, cg).cs_nffree < ffs_numfrags(fs, nsize - osize))
return (0);
frags = numfrags(fs, nsize);
bbase = fragnum(fs, bprev);
if (bbase > fragnum(fs, (bprev + frags - 1))) {
frags = ffs_numfrags(fs, nsize);
bbase = ffs_fragnum(fs, bprev);
if (bbase > ffs_fragnum(fs, (bprev + frags - 1))) {
/* cannot extend across a block boundary */
return (0);
}
mutex_exit(&ump->um_lock);
error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
error = bread(ip->i_devvp, FFS_FSBTODB(fs, cgtod(fs, cg)),
(int)fs->fs_cgsize, NOCRED, B_MODIFY, &bp);
if (error)
goto fail;
@@ -1041,7 +1043,7 @@ ffs_fragextend(struct inode *ip, int cg, daddr_t bprev, int osize, int nsize)
cgp->cg_time = ufs_rw64(time_second, UFS_FSNEEDSWAP(fs));
bno = dtogd(fs, bprev);
blksfree = cg_blksfree(cgp, UFS_FSNEEDSWAP(fs));
for (i = numfrags(fs, osize); i < frags; i++)
for (i = ffs_numfrags(fs, osize); i < frags; i++)
if (isclr(blksfree, bno + i))
goto fail;
/*
@@ -1053,11 +1055,11 @@ ffs_fragextend(struct inode *ip, int cg, daddr_t bprev, int osize, int nsize)
for (i = frags; i < fs->fs_frag - bbase; i++)
if (isclr(blksfree, bno + i))
break;
ufs_add32(cgp->cg_frsum[i - numfrags(fs, osize)], -1, UFS_FSNEEDSWAP(fs));
ufs_add32(cgp->cg_frsum[i - ffs_numfrags(fs, osize)], -1, UFS_FSNEEDSWAP(fs));
if (i != frags)
ufs_add32(cgp->cg_frsum[i - frags], 1, UFS_FSNEEDSWAP(fs));
mutex_enter(&ump->um_lock);
for (i = numfrags(fs, osize); i < frags; i++) {
for (i = ffs_numfrags(fs, osize); i < frags; i++) {
clrbit(blksfree, bno + i);
ufs_add32(cgp->cg_cs.cs_nffree, -1, UFS_FSNEEDSWAP(fs));
fs->fs_cstotal.cs_nffree--;
@@ -1070,7 +1072,8 @@ ffs_fragextend(struct inode *ip, int cg, daddr_t bprev, int osize, int nsize)
return (bprev);
fail:
brelse(bp, 0);
if (bp != NULL)
brelse(bp, 0);
mutex_enter(&ump->um_lock);
return (0);
}
@@ -1092,9 +1095,7 @@ ffs_alloccg(struct inode *ip, int cg, daddr_t bpref, int size, int flags)
daddr_t blkno;
int error, frags, allocsiz, i;
u_int8_t *blksfree;
#ifdef FFS_EI
const int needswap = UFS_FSNEEDSWAP(fs);
#endif
ump = ip->i_ump;
@@ -1103,7 +1104,7 @@ ffs_alloccg(struct inode *ip, int cg, daddr_t bpref, int size, int flags)
if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize)
return (0);
mutex_exit(&ump->um_lock);
error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
error = bread(ip->i_devvp, FFS_FSBTODB(fs, cgtod(fs, cg)),
(int)fs->fs_cgsize, NOCRED, B_MODIFY, &bp);
if (error)
goto fail;
@@ -1129,7 +1130,7 @@ ffs_alloccg(struct inode *ip, int cg, daddr_t bpref, int size, int flags)
* it down to a smaller size if necessary
*/
blksfree = cg_blksfree(cgp, needswap);
frags = numfrags(fs, size);
frags = ffs_numfrags(fs, size);
for (allocsiz = frags; allocsiz < fs->fs_frag; allocsiz++)
if (cgp->cg_frsum[allocsiz] != 0)
break;
@@ -1182,7 +1183,8 @@ ffs_alloccg(struct inode *ip, int cg, daddr_t bpref, int size, int flags)
return blkno;
fail:
brelse(bp, 0);
if (bp != NULL)
brelse(bp, 0);
mutex_enter(&ump->um_lock);
return (0);
}
@@ -1201,32 +1203,27 @@ ffs_alloccg(struct inode *ip, int cg, daddr_t bpref, int size, int flags)
static daddr_t
ffs_alloccgblk(struct inode *ip, struct buf *bp, daddr_t bpref, int flags)
{
struct ufsmount *ump;
struct fs *fs = ip->i_fs;
struct cg *cgp;
int cg;
daddr_t blkno;
int32_t bno;
u_int8_t *blksfree;
#ifdef FFS_EI
const int needswap = UFS_FSNEEDSWAP(fs);
#endif
ump = ip->i_ump;
KASSERT(mutex_owned(&ump->um_lock));
KASSERT(mutex_owned(&ip->i_ump->um_lock));
cgp = (struct cg *)bp->b_data;
blksfree = cg_blksfree(cgp, needswap);
if (bpref == 0 || dtog(fs, bpref) != ufs_rw32(cgp->cg_cgx, needswap)) {
bpref = ufs_rw32(cgp->cg_rotor, needswap);
} else {
bpref = blknum(fs, bpref);
bpref = ffs_blknum(fs, bpref);
bno = dtogd(fs, bpref);
/*
* if the requested block is available, use it
*/
if (ffs_isblock(fs, blksfree, fragstoblks(fs, bno)))
if (ffs_isblock(fs, blksfree, ffs_fragstoblks(fs, bno)))
goto gotit;
/*
* if the requested data block isn't available and we are
@@ -1244,7 +1241,7 @@ ffs_alloccgblk(struct inode *ip, struct buf *bp, daddr_t bpref, int flags)
return (0);
cgp->cg_rotor = ufs_rw32(bno, needswap);
gotit:
blkno = fragstoblks(fs, bno);
blkno = ffs_fragstoblks(fs, bno);
ffs_clrblock(fs, blksfree, blkno);
ffs_clusteracct(fs, cgp, blkno, -1);
ufs_add32(cgp->cg_cs.cs_nbfree, -1, needswap);
@@ -1289,9 +1286,7 @@ ffs_nodealloccg(struct inode *ip, int cg, daddr_t ipref, int mode, int flags)
int32_t initediblk;
daddr_t nalloc;
struct ufs2_dinode *dp2;
#ifdef FFS_EI
const int needswap = UFS_FSNEEDSWAP(fs);
#endif
KASSERT(mutex_owned(&ump->um_lock));
UFS_WAPBL_JLOCK_ASSERT(ip->i_ump->um_mountp);
@@ -1302,7 +1297,7 @@ ffs_nodealloccg(struct inode *ip, int cg, daddr_t ipref, int mode, int flags)
ibp = NULL;
initediblk = -1;
retry:
error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
error = bread(ip->i_devvp, FFS_FSBTODB(fs, cgtod(fs, cg)),
(int)fs->fs_cgsize, NOCRED, B_MODIFY, &bp);
if (error)
goto fail;
@@ -1322,7 +1317,7 @@ retry:
if (fs->fs_magic == FS_UFS2_MAGIC && ibp == NULL) {
initediblk = ufs_rw32(cgp->cg_initediblk, needswap);
nalloc = fs->fs_ipg - ufs_rw32(cgp->cg_cs.cs_nifree, needswap);
if (nalloc + INOPB(fs) > initediblk &&
if (nalloc + FFS_INOPB(fs) > initediblk &&
initediblk < ufs_rw32(cgp->cg_niblk, needswap)) {
/*
* We have to release the cg buffer here to prevent
@@ -1331,7 +1326,7 @@ retry:
*/
brelse(bp, 0);
bp = NULL;
error = ffs_getblk(ip->i_devvp, fsbtodb(fs,
error = ffs_getblk(ip->i_devvp, FFS_FSBTODB(fs,
ino_to_fsba(fs, cg * fs->fs_ipg + initediblk)),
FFS_NOBLK, fs->fs_bsize, false, &ibp);
if (error)
@@ -1384,7 +1379,7 @@ gotit:
KASSERT(initediblk == ufs_rw32(cgp->cg_initediblk, needswap));
memset(ibp->b_data, 0, fs->fs_bsize);
dp2 = (struct ufs2_dinode *)(ibp->b_data);
for (i = 0; i < INOPB(fs); i++) {
for (i = 0; i < FFS_INOPB(fs); i++) {
/*
* Don't bother to swap, it's supposed to be
* random, after all.
@@ -1392,7 +1387,7 @@ gotit:
dp2->di_gen = (cprng_fast32() & INT32_MAX) / 2 + 1;
dp2++;
}
initediblk += INOPB(fs);
initediblk += FFS_INOPB(fs);
cgp->cg_initediblk = ufs_rw32(initediblk, needswap);
}
@@ -1458,15 +1453,14 @@ ffs_blkalloc_ump(struct ufsmount *ump, daddr_t bno, long size)
u_int8_t *blksfree;
const int needswap = UFS_FSNEEDSWAP(fs);
KASSERT((u_int)size <= fs->fs_bsize && fragoff(fs, size) == 0 &&
fragnum(fs, bno) + numfrags(fs, size) <= fs->fs_frag);
KASSERT((u_int)size <= fs->fs_bsize && ffs_fragoff(fs, size) == 0 &&
ffs_fragnum(fs, bno) + ffs_numfrags(fs, size) <= fs->fs_frag);
KASSERT(bno < fs->fs_size);
cg = dtog(fs, bno);
error = bread(ump->um_devvp, fsbtodb(fs, cgtod(fs, cg)),
error = bread(ump->um_devvp, FFS_FSBTODB(fs, cgtod(fs, cg)),
(int)fs->fs_cgsize, NOCRED, B_MODIFY, &bp);
if (error) {
brelse(bp, 0);
return error;
}
cgp = (struct cg *)bp->b_data;
@@ -1481,7 +1475,7 @@ ffs_blkalloc_ump(struct ufsmount *ump, daddr_t bno, long size)
mutex_enter(&ump->um_lock);
if (size == fs->fs_bsize) {
fragno = fragstoblks(fs, cgbno);
fragno = ffs_fragstoblks(fs, cgbno);
if (!ffs_isblock(fs, blksfree, fragno)) {
mutex_exit(&ump->um_lock);
brelse(bp, 0);
@@ -1493,9 +1487,9 @@ ffs_blkalloc_ump(struct ufsmount *ump, daddr_t bno, long size)
fs->fs_cstotal.cs_nbfree--;
fs->fs_cs(fs, cg).cs_nbfree--;
} else {
bbase = cgbno - fragnum(fs, cgbno);
bbase = cgbno - ffs_fragnum(fs, cgbno);
frags = numfrags(fs, size);
frags = ffs_numfrags(fs, size);
for (i = 0; i < frags; i++) {
if (isclr(blksfree, cgbno + i)) {
mutex_exit(&ump->um_lock);
@@ -1506,7 +1500,7 @@ ffs_blkalloc_ump(struct ufsmount *ump, daddr_t bno, long size)
/*
* if a complete block is being split, account for it
*/
fragno = fragstoblks(fs, bbase);
fragno = ffs_fragstoblks(fs, bbase);
if (ffs_isblock(fs, blksfree, fragno)) {
ufs_add32(cgp->cg_cs.cs_nffree, fs->fs_frag, needswap);
fs->fs_cstotal.cs_nffree += fs->fs_frag;
@@ -1552,9 +1546,8 @@ ffs_blkalloc_ump(struct ufsmount *ump, daddr_t bno, long size)
*
* => um_lock not held on entry or exit
*/
void
ffs_blkfree(struct fs *fs, struct vnode *devvp, daddr_t bno, long size,
ino_t inum)
static void
ffs_blkfree_cg(struct fs *fs, struct vnode *devvp, daddr_t bno, long size)
{
struct cg *cgp;
struct buf *bp;
@@ -1563,28 +1556,19 @@ ffs_blkfree(struct fs *fs, struct vnode *devvp, daddr_t bno, long size,
int error, cg;
dev_t dev;
const bool devvp_is_snapshot = (devvp->v_type != VBLK);
#ifdef FFS_EI
const int needswap = UFS_FSNEEDSWAP(fs);
#endif
KASSERT(!devvp_is_snapshot);
cg = dtog(fs, bno);
dev = devvp->v_rdev;
ump = VFSTOUFS(devvp->v_specmountpoint);
ump = VFSTOUFS(spec_node_getmountedfs(devvp));
KASSERT(fs == ump->um_fs);
cgblkno = fsbtodb(fs, cgtod(fs, cg));
if (ffs_snapblkfree(fs, devvp, bno, size, inum))
return;
error = ffs_check_bad_allocation(__func__, fs, bno, size, dev, inum);
if (error)
return;
cgblkno = FFS_FSBTODB(fs, cgtod(fs, cg));
error = bread(devvp, cgblkno, (int)fs->fs_cgsize,
NOCRED, B_MODIFY, &bp);
if (error) {
brelse(bp, 0);
return;
}
cgp = (struct cg *)bp->b_data;
@@ -1598,6 +1582,230 @@ ffs_blkfree(struct fs *fs, struct vnode *devvp, daddr_t bno, long size,
bdwrite(bp);
}
struct discardopdata {
struct work wk; /* must be first */
struct vnode *devvp;
daddr_t bno;
long size;
};
struct discarddata {
struct fs *fs;
struct discardopdata *entry;
long maxsize;
kmutex_t entrylk;
struct workqueue *wq;
int wqcnt, wqdraining;
kmutex_t wqlk;
kcondvar_t wqcv;
/* timer for flush? */
};
static void
ffs_blkfree_td(struct fs *fs, struct discardopdata *td)
{
long todo;
while (td->size) {
todo = min(td->size,
ffs_lfragtosize(fs, (fs->fs_frag - ffs_fragnum(fs, td->bno))));
ffs_blkfree_cg(fs, td->devvp, td->bno, todo);
td->bno += ffs_numfrags(fs, todo);
td->size -= todo;
}
}
static void
ffs_discardcb(struct work *wk, void *arg)
{
struct discardopdata *td = (void *)wk;
struct discarddata *ts = arg;
struct fs *fs = ts->fs;
struct disk_discard_range ta;
#ifdef TRIMDEBUG
int error;
#endif
ta.bno = FFS_FSBTODB(fs, td->bno);
ta.size = td->size >> DEV_BSHIFT;
#ifdef TRIMDEBUG
error =
#endif
VOP_IOCTL(td->devvp, DIOCDISCARD, &ta, FWRITE, FSCRED);
#ifdef TRIMDEBUG
printf("trim(%" PRId64 ",%ld):%d\n", td->bno, td->size, error);
#endif
ffs_blkfree_td(fs, td);
kmem_free(td, sizeof(*td));
mutex_enter(&ts->wqlk);
ts->wqcnt--;
if (ts->wqdraining && !ts->wqcnt)
cv_signal(&ts->wqcv);
mutex_exit(&ts->wqlk);
}
void *
ffs_discard_init(struct vnode *devvp, struct fs *fs)
{
struct disk_discard_params tp;
struct discarddata *ts;
int error;
error = VOP_IOCTL(devvp, DIOCGDISCARDPARAMS, &tp, FREAD, FSCRED);
if (error) {
printf("DIOCGDISCARDPARAMS: %d\n", error);
return NULL;
}
if (tp.maxsize * DEV_BSIZE < fs->fs_bsize) {
printf("tp.maxsize=%ld, fs_bsize=%d\n", tp.maxsize, fs->fs_bsize);
return NULL;
}
ts = kmem_zalloc(sizeof (*ts), KM_SLEEP);
error = workqueue_create(&ts->wq, "trimwq", ffs_discardcb, ts,
0, 0, 0);
if (error) {
kmem_free(ts, sizeof (*ts));
return NULL;
}
mutex_init(&ts->entrylk, MUTEX_DEFAULT, IPL_NONE);
mutex_init(&ts->wqlk, MUTEX_DEFAULT, IPL_NONE);
cv_init(&ts->wqcv, "trimwqcv");
ts->maxsize = max(tp.maxsize * DEV_BSIZE, 100*1024); /* XXX */
ts->fs = fs;
return ts;
}
void
ffs_discard_finish(void *vts, int flags)
{
struct discarddata *ts = vts;
struct discardopdata *td = NULL;
int res = 0;
/* wait for workqueue to drain */
mutex_enter(&ts->wqlk);
if (ts->wqcnt) {
ts->wqdraining = 1;
res = cv_timedwait(&ts->wqcv, &ts->wqlk, mstohz(5000));
}
mutex_exit(&ts->wqlk);
if (res)
printf("ffs_discarddata drain timeout\n");
mutex_enter(&ts->entrylk);
if (ts->entry) {
td = ts->entry;
ts->entry = NULL;
}
mutex_exit(&ts->entrylk);
if (td) {
/* XXX don't tell disk, its optional */
ffs_blkfree_td(ts->fs, td);
#ifdef TRIMDEBUG
printf("finish(%" PRId64 ",%ld)\n", td->bno, td->size);
#endif
kmem_free(td, sizeof(*td));
}
cv_destroy(&ts->wqcv);
mutex_destroy(&ts->entrylk);
mutex_destroy(&ts->wqlk);
workqueue_destroy(ts->wq);
kmem_free(ts, sizeof(*ts));
}
void
ffs_blkfree(struct fs *fs, struct vnode *devvp, daddr_t bno, long size,
ino_t inum)
{
struct ufsmount *ump;
int error;
dev_t dev;
struct discarddata *ts;
struct discardopdata *td;
dev = devvp->v_rdev;
ump = VFSTOUFS(spec_node_getmountedfs(devvp));
if (ffs_snapblkfree(fs, devvp, bno, size, inum))
return;
error = ffs_check_bad_allocation(__func__, fs, bno, size, dev, inum);
if (error)
return;
if (!ump->um_discarddata) {
ffs_blkfree_cg(fs, devvp, bno, size);
return;
}
#ifdef TRIMDEBUG
printf("blkfree(%" PRId64 ",%ld)\n", bno, size);
#endif
ts = ump->um_discarddata;
td = NULL;
mutex_enter(&ts->entrylk);
if (ts->entry) {
td = ts->entry;
/* ffs deallocs backwards, check for prepend only */
if (td->bno == bno + ffs_numfrags(fs, size)
&& td->size + size <= ts->maxsize) {
td->bno = bno;
td->size += size;
if (td->size < ts->maxsize) {
#ifdef TRIMDEBUG
printf("defer(%" PRId64 ",%ld)\n", td->bno, td->size);
#endif
mutex_exit(&ts->entrylk);
return;
}
size = 0; /* mark done */
}
ts->entry = NULL;
}
mutex_exit(&ts->entrylk);
if (td) {
#ifdef TRIMDEBUG
printf("enq old(%" PRId64 ",%ld)\n", td->bno, td->size);
#endif
mutex_enter(&ts->wqlk);
ts->wqcnt++;
mutex_exit(&ts->wqlk);
workqueue_enqueue(ts->wq, &td->wk, NULL);
}
if (!size)
return;
td = kmem_alloc(sizeof(*td), KM_SLEEP);
td->devvp = devvp;
td->bno = bno;
td->size = size;
if (td->size < ts->maxsize) { /* XXX always the case */
mutex_enter(&ts->entrylk);
if (!ts->entry) { /* possible race? */
#ifdef TRIMDEBUG
printf("defer(%" PRId64 ",%ld)\n", td->bno, td->size);
#endif
ts->entry = td;
td = NULL;
}
mutex_exit(&ts->entrylk);
}
if (td) {
#ifdef TRIMDEBUG
printf("enq new(%" PRId64 ",%ld)\n", td->bno, td->size);
#endif
mutex_enter(&ts->wqlk);
ts->wqcnt++;
mutex_exit(&ts->wqlk);
workqueue_enqueue(ts->wq, &td->wk, NULL);
}
}
/*
* Free a block or fragment from a snapshot cg copy.
*
@@ -1618,16 +1826,14 @@ ffs_blkfree_snap(struct fs *fs, struct vnode *devvp, daddr_t bno, long size,
int error, cg;
dev_t dev;
const bool devvp_is_snapshot = (devvp->v_type != VBLK);
#ifdef FFS_EI
const int needswap = UFS_FSNEEDSWAP(fs);
#endif
KASSERT(devvp_is_snapshot);
cg = dtog(fs, bno);
dev = VTOI(devvp)->i_devvp->v_rdev;
ump = VFSTOUFS(devvp->v_mount);
cgblkno = fragstoblks(fs, cgtod(fs, cg));
cgblkno = ffs_fragstoblks(fs, cgtod(fs, cg));
error = ffs_check_bad_allocation(__func__, fs, bno, size, dev, inum);
if (error)
@@ -1636,7 +1842,6 @@ ffs_blkfree_snap(struct fs *fs, struct vnode *devvp, daddr_t bno, long size,
error = bread(devvp, cgblkno, (int)fs->fs_cgsize,
NOCRED, B_MODIFY, &bp);
if (error) {
brelse(bp, 0);
return;
}
cgp = (struct cg *)bp->b_data;
@@ -1670,7 +1875,7 @@ ffs_blkfree_common(struct ufsmount *ump, struct fs *fs, dev_t dev,
blksfree = cg_blksfree(cgp, needswap);
mutex_enter(&ump->um_lock);
if (size == fs->fs_bsize) {
fragno = fragstoblks(fs, cgbno);
fragno = ffs_fragstoblks(fs, cgbno);
if (!ffs_isfreeblock(fs, blksfree, fragno)) {
if (devvp_is_snapshot) {
mutex_exit(&ump->um_lock);
@@ -1697,7 +1902,7 @@ ffs_blkfree_common(struct ufsmount *ump, struct fs *fs, dev_t dev,
ufs_add32(old_cg_blktot(cgp, needswap)[i], 1, needswap);
}
} else {
bbase = cgbno - fragnum(fs, cgbno);
bbase = cgbno - ffs_fragnum(fs, cgbno);
/*
* decrement the counts associated with the old frags
*/
@@ -1706,7 +1911,7 @@ ffs_blkfree_common(struct ufsmount *ump, struct fs *fs, dev_t dev,
/*
* deallocate the fragment
*/
frags = numfrags(fs, size);
frags = ffs_numfrags(fs, size);
for (i = 0; i < frags; i++) {
if (isset(blksfree, cgbno + i)) {
printf("dev = 0x%llx, block = %" PRId64
@@ -1728,7 +1933,7 @@ ffs_blkfree_common(struct ufsmount *ump, struct fs *fs, dev_t dev,
/*
* if a complete block has been reassembled, account for it
*/
fragno = fragstoblks(fs, bbase);
fragno = ffs_fragstoblks(fs, bbase);
if (ffs_isblock(fs, blksfree, fragno)) {
ufs_add32(cgp->cg_cs.cs_nffree, -fs->fs_frag, needswap);
fs->fs_cstotal.cs_nffree -= fs->fs_frag;
@@ -1782,14 +1987,12 @@ ffs_freefile(struct mount *mp, ino_t ino, int mode)
int error, cg;
daddr_t cgbno;
dev_t dev;
#ifdef FFS_EI
const int needswap = UFS_FSNEEDSWAP(fs);
#endif
cg = ino_to_cg(fs, ino);
devvp = ump->um_devvp;
dev = devvp->v_rdev;
cgbno = fsbtodb(fs, cgtod(fs, cg));
cgbno = FFS_FSBTODB(fs, cgtod(fs, cg));
if ((u_int)ino >= fs->fs_ipg * fs->fs_ncg)
panic("ifree: range: dev = 0x%llx, ino = %llu, fs = %s",
@@ -1797,7 +2000,6 @@ ffs_freefile(struct mount *mp, ino_t ino, int mode)
error = bread(devvp, cgbno, (int)fs->fs_cgsize,
NOCRED, B_MODIFY, &bp);
if (error) {
brelse(bp, 0);
return (error);
}
cgp = (struct cg *)bp->b_data;
@@ -1822,16 +2024,14 @@ ffs_freefile_snap(struct fs *fs, struct vnode *devvp, ino_t ino, int mode)
int error, cg;
daddr_t cgbno;
dev_t dev;
#ifdef FFS_EI
const int needswap = UFS_FSNEEDSWAP(fs);
#endif
KASSERT(devvp->v_type != VBLK);
cg = ino_to_cg(fs, ino);
dev = VTOI(devvp)->i_devvp->v_rdev;
ump = VFSTOUFS(devvp->v_mount);
cgbno = fragstoblks(fs, cgtod(fs, cg));
cgbno = ffs_fragstoblks(fs, cgtod(fs, cg));
if ((u_int)ino >= fs->fs_ipg * fs->fs_ncg)
panic("ifree: range: dev = 0x%llx, ino = %llu, fs = %s",
(unsigned long long)dev, (unsigned long long)ino,
@@ -1839,7 +2039,6 @@ ffs_freefile_snap(struct fs *fs, struct vnode *devvp, ino_t ino, int mode)
error = bread(devvp, cgbno, (int)fs->fs_cgsize,
NOCRED, B_MODIFY, &bp);
if (error) {
brelse(bp, 0);
return (error);
}
cgp = (struct cg *)bp->b_data;
@@ -1861,9 +2060,7 @@ ffs_freefile_common(struct ufsmount *ump, struct fs *fs, dev_t dev,
int cg;
struct cg *cgp;
u_int8_t *inosused;
#ifdef FFS_EI
const int needswap = UFS_FSNEEDSWAP(fs);
#endif
cg = ino_to_cg(fs, ino);
cgp = (struct cg *)bp->b_data;
@@ -1917,13 +2114,12 @@ ffs_checkfreefile(struct fs *fs, struct vnode *devvp, ino_t ino)
cg = ino_to_cg(fs, ino);
if (devvp_is_snapshot)
cgbno = fragstoblks(fs, cgtod(fs, cg));
cgbno = ffs_fragstoblks(fs, cgtod(fs, cg));
else
cgbno = fsbtodb(fs, cgtod(fs, cg));
cgbno = FFS_FSBTODB(fs, cgtod(fs, cg));
if ((u_int)ino >= fs->fs_ipg * fs->fs_ncg)
return 1;
if (bread(devvp, cgbno, (int)fs->fs_cgsize, NOCRED, 0, &bp)) {
brelse(bp, 0);
return 1;
}
cgp = (struct cg *)bp->b_data;
@@ -1952,9 +2148,7 @@ ffs_mapsearch(struct fs *fs, struct cg *cgp, daddr_t bpref, int allocsiz)
int blk, field, subfield, pos;
int ostart, olen;
u_int8_t *blksfree;
#ifdef FFS_EI
const int needswap = UFS_FSNEEDSWAP(fs);
#endif
/* KASSERT(mutex_owned(&ump->um_lock)); */
+57 -73
View File
@@ -1,4 +1,4 @@
/* $NetBSD: ffs_balloc.c,v 1.54 2011/04/23 07:36:02 hannken Exp $ */
/* $NetBSD: ffs_balloc.c,v 1.60 2013/10/20 00:29:10 htodd Exp $ */
/*
* Copyright (c) 2002 Networks Associates Technology, Inc.
@@ -41,7 +41,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ffs_balloc.c,v 1.54 2011/04/23 07:36:02 hannken Exp $");
__KERNEL_RCSID(0, "$NetBSD: ffs_balloc.c,v 1.60 2013/10/20 00:29:10 htodd Exp $");
#if defined(_KERNEL_OPT)
#include "opt_quota.h"
@@ -104,20 +104,18 @@ ffs_balloc_ufs1(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
struct inode *ip = VTOI(vp);
struct fs *fs = ip->i_fs;
struct ufsmount *ump = ip->i_ump;
struct indir indirs[NIADDR + 2];
struct indir indirs[UFS_NIADDR + 2];
daddr_t newb, pref, nb;
int32_t *bap; /* XXX ondisk32 */
int deallocated, osize, nsize, num, i, error;
int32_t *blkp, *allocblk, allociblk[NIADDR + 1];
int32_t *blkp, *allocblk, allociblk[UFS_NIADDR + 1];
int32_t *allocib;
int unwindidx = -1;
#ifdef FFS_EI
const int needswap = UFS_FSNEEDSWAP(fs);
#endif
UVMHIST_FUNC("ffs_balloc"); UVMHIST_CALLED(ubchist);
lbn = lblkno(fs, off);
size = blkoff(fs, off) + size;
lbn = ffs_lblkno(fs, off);
size = ffs_blkoff(fs, off) + size;
if (size > fs->fs_bsize)
panic("ffs_balloc: blk too big");
if (bpp != NULL) {
@@ -134,10 +132,10 @@ ffs_balloc_ufs1(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
* this fragment has to be extended to be a full block.
*/
lastlbn = lblkno(fs, ip->i_size);
if (lastlbn < NDADDR && lastlbn < lbn) {
lastlbn = ffs_lblkno(fs, ip->i_size);
if (lastlbn < UFS_NDADDR && lastlbn < lbn) {
nb = lastlbn;
osize = blksize(fs, ip, nb);
osize = ffs_blksize(fs, ip, nb);
if (osize < fs->fs_bsize && osize > 0) {
mutex_enter(&ump->um_lock);
error = ffs_realloccg(ip, nb,
@@ -146,7 +144,7 @@ ffs_balloc_ufs1(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
osize, (int)fs->fs_bsize, cred, bpp, &newb);
if (error)
return (error);
ip->i_size = lblktosize(fs, nb + 1);
ip->i_size = ffs_lblktosize(fs, nb + 1);
ip->i_ffs1_size = ip->i_size;
uvm_vnp_setsize(vp, ip->i_ffs1_size);
ip->i_ffs1_db[nb] = ufs_rw32((u_int32_t)newb, needswap);
@@ -161,12 +159,12 @@ ffs_balloc_ufs1(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
}
/*
* The first NDADDR blocks are direct blocks
* The first UFS_NDADDR blocks are direct blocks
*/
if (lbn < NDADDR) {
if (lbn < UFS_NDADDR) {
nb = ufs_rw32(ip->i_ffs1_db[lbn], needswap);
if (nb != 0 && ip->i_size >= lblktosize(fs, lbn + 1)) {
if (nb != 0 && ip->i_size >= ffs_lblktosize(fs, lbn + 1)) {
/*
* The block is an already-allocated direct block
@@ -179,7 +177,6 @@ ffs_balloc_ufs1(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
error = bread(vp, lbn, fs->fs_bsize, NOCRED,
B_MODIFY, bpp);
if (error) {
brelse(*bpp, 0);
return (error);
}
}
@@ -191,8 +188,8 @@ ffs_balloc_ufs1(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
* Consider need to reallocate a fragment.
*/
osize = fragroundup(fs, blkoff(fs, ip->i_size));
nsize = fragroundup(fs, size);
osize = ffs_fragroundup(fs, ffs_blkoff(fs, ip->i_size));
nsize = ffs_fragroundup(fs, size);
if (nsize <= osize) {
/*
@@ -205,7 +202,6 @@ ffs_balloc_ufs1(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
error = bread(vp, lbn, osize, NOCRED,
B_MODIFY, bpp);
if (error) {
brelse(*bpp, 0);
return (error);
}
}
@@ -231,8 +227,8 @@ ffs_balloc_ufs1(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
* allocate a new block or fragment.
*/
if (ip->i_size < lblktosize(fs, lbn + 1))
nsize = fragroundup(fs, size);
if (ip->i_size < ffs_lblktosize(fs, lbn + 1))
nsize = ffs_fragroundup(fs, size);
else
nsize = fs->fs_bsize;
mutex_enter(&ump->um_lock);
@@ -243,7 +239,7 @@ ffs_balloc_ufs1(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
if (error)
return (error);
if (bpp != NULL) {
error = ffs_getblk(vp, lbn, fsbtodb(fs, newb),
error = ffs_getblk(vp, lbn, FFS_FSBTODB(fs, newb),
nsize, (flags & B_CLRBUF) != 0, bpp);
if (error)
return error;
@@ -279,7 +275,7 @@ ffs_balloc_ufs1(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
goto fail;
nb = newb;
*allocblk++ = nb;
error = ffs_getblk(vp, indirs[1].in_lbn, fsbtodb(fs, nb),
error = ffs_getblk(vp, indirs[1].in_lbn, FFS_FSBTODB(fs, nb),
fs->fs_bsize, true, &bp);
if (error)
goto fail;
@@ -303,7 +299,6 @@ ffs_balloc_ufs1(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
error = bread(vp,
indirs[i].in_lbn, (int)fs->fs_bsize, NOCRED, 0, &bp);
if (error) {
brelse(bp, 0);
goto fail;
}
bap = (int32_t *)bp->b_data; /* XXX ondisk32 */
@@ -335,7 +330,7 @@ ffs_balloc_ufs1(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
}
nb = newb;
*allocblk++ = nb;
error = ffs_getblk(vp, indirs[i].in_lbn, fsbtodb(fs, nb),
error = ffs_getblk(vp, indirs[i].in_lbn, FFS_FSBTODB(fs, nb),
fs->fs_bsize, true, &nbp);
if (error) {
brelse(bp, 0);
@@ -392,7 +387,7 @@ ffs_balloc_ufs1(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
nb = newb;
*allocblk++ = nb;
if (bpp != NULL) {
error = ffs_getblk(vp, lbn, fsbtodb(fs, nb),
error = ffs_getblk(vp, lbn, FFS_FSBTODB(fs, nb),
fs->fs_bsize, (flags & B_CLRBUF) != 0, bpp);
if (error) {
brelse(bp, 0);
@@ -422,11 +417,10 @@ ffs_balloc_ufs1(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
error = bread(vp, lbn, (int)fs->fs_bsize,
NOCRED, B_MODIFY, &nbp);
if (error) {
brelse(nbp, 0);
goto fail;
}
} else {
error = ffs_getblk(vp, lbn, fsbtodb(fs, nb),
error = ffs_getblk(vp, lbn, FFS_FSBTODB(fs, nb),
fs->fs_bsize, true, &nbp);
if (error)
goto fail;
@@ -458,8 +452,8 @@ fail:
fs->fs_bsize, false, &bp) != 0)
continue;
if (bp->b_oflags & BO_DELWRI) {
nb = fsbtodb(fs, cgtod(fs, dtog(fs,
dbtofsb(fs, bp->b_blkno))));
nb = FFS_FSBTODB(fs, cgtod(fs, dtog(fs,
FFS_DBTOFSB(fs, bp->b_blkno))));
bwrite(bp);
if (ffs_getblk(ip->i_devvp, nb, FFS_NOBLK,
fs->fs_cgsize, false, &bp) != 0)
@@ -487,7 +481,6 @@ fail:
(int)fs->fs_bsize, NOCRED, 0, &bp);
if (r) {
panic("Could not unwind indirect block, error %d", r);
brelse(bp, 0);
} else {
bap = (int32_t *)bp->b_data; /* XXX ondisk32 */
bap[indirs[unwindidx].in_off] = 0;
@@ -526,20 +519,18 @@ ffs_balloc_ufs2(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
struct inode *ip = VTOI(vp);
struct fs *fs = ip->i_fs;
struct ufsmount *ump = ip->i_ump;
struct indir indirs[NIADDR + 2];
struct indir indirs[UFS_NIADDR + 2];
daddr_t newb, pref, nb;
int64_t *bap;
int deallocated, osize, nsize, num, i, error;
daddr_t *blkp, *allocblk, allociblk[NIADDR + 1];
daddr_t *blkp, *allocblk, allociblk[UFS_NIADDR + 1];
int64_t *allocib;
int unwindidx = -1;
#ifdef FFS_EI
const int needswap = UFS_FSNEEDSWAP(fs);
#endif
UVMHIST_FUNC("ffs_balloc"); UVMHIST_CALLED(ubchist);
lbn = lblkno(fs, off);
size = blkoff(fs, off) + size;
lbn = ffs_lblkno(fs, off);
size = ffs_blkoff(fs, off) + size;
if (size > fs->fs_bsize)
panic("ffs_balloc: blk too big");
if (bpp != NULL) {
@@ -555,17 +546,17 @@ ffs_balloc_ufs2(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
* Check for allocating external data.
*/
if (flags & IO_EXT) {
if (lbn >= NXADDR)
if (lbn >= UFS_NXADDR)
return (EFBIG);
/*
* If the next write will extend the data into a new block,
* and the data is currently composed of a fragment
* this fragment has to be extended to be a full block.
*/
lastlbn = lblkno(fs, dp->di_extsize);
lastlbn = ffs_lblkno(fs, dp->di_extsize);
if (lastlbn < lbn) {
nb = lastlbn;
osize = sblksize(fs, dp->di_extsize, nb);
osize = ffs_sblksize(fs, dp->di_extsize, nb);
if (osize < fs->fs_bsize && osize > 0) {
mutex_enter(&ump->um_lock);
error = ffs_realloccg(ip, -1 - nb,
@@ -577,7 +568,7 @@ ffs_balloc_ufs2(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
if (error)
return (error);
dp->di_extsize = smalllblktosize(fs, nb + 1);
dp->di_extb[nb] = dbtofsb(fs, bp->b_blkno);
dp->di_extb[nb] = FFS_DBTOFSB(fs, bp->b_blkno);
bp->b_xflags |= BX_ALTDATA;
ip->i_flag |= IN_CHANGE | IN_UPDATE;
if (flags & IO_SYNC)
@@ -596,11 +587,10 @@ ffs_balloc_ufs2(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
error = bread(vp, -1 - lbn, fs->fs_bsize,
NOCRED, 0, &bp);
if (error) {
brelse(bp, 0);
return (error);
}
mutex_enter(&bp->b_interlock);
bp->b_blkno = fsbtodb(fs, nb);
bp->b_blkno = FFS_FSBTODB(fs, nb);
bp->b_xflags |= BX_ALTDATA;
mutex_exit(&bp->b_interlock);
*bpp = bp;
@@ -610,17 +600,16 @@ ffs_balloc_ufs2(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
/*
* Consider need to reallocate a fragment.
*/
osize = fragroundup(fs, blkoff(fs, dp->di_extsize));
nsize = fragroundup(fs, size);
osize = ffs_fragroundup(fs, ffs_blkoff(fs, dp->di_extsize));
nsize = ffs_fragroundup(fs, size);
if (nsize <= osize) {
error = bread(vp, -1 - lbn, osize,
NOCRED, 0, &bp);
if (error) {
brelse(bp, 0);
return (error);
}
mutex_enter(&bp->b_interlock);
bp->b_blkno = fsbtodb(fs, nb);
bp->b_blkno = FFS_FSBTODB(fs, nb);
bp->b_xflags |= BX_ALTDATA;
mutex_exit(&bp->b_interlock);
} else {
@@ -636,7 +625,7 @@ ffs_balloc_ufs2(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
}
} else {
if (dp->di_extsize < smalllblktosize(fs, lbn + 1))
nsize = fragroundup(fs, size);
nsize = ffs_fragroundup(fs, size);
else
nsize = fs->fs_bsize;
mutex_enter(&ump->um_lock);
@@ -646,13 +635,13 @@ ffs_balloc_ufs2(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
nsize, flags, cred, &newb);
if (error)
return (error);
error = ffs_getblk(vp, -1 - lbn, fsbtodb(fs, newb),
error = ffs_getblk(vp, -1 - lbn, FFS_FSBTODB(fs, newb),
nsize, (flags & BA_CLRBUF) != 0, &bp);
if (error)
return error;
bp->b_xflags |= BX_ALTDATA;
}
dp->di_extb[lbn] = dbtofsb(fs, bp->b_blkno);
dp->di_extb[lbn] = FFS_DBTOFSB(fs, bp->b_blkno);
ip->i_flag |= IN_CHANGE | IN_UPDATE;
*bpp = bp;
return (0);
@@ -664,10 +653,10 @@ ffs_balloc_ufs2(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
* this fragment has to be extended to be a full block.
*/
lastlbn = lblkno(fs, ip->i_size);
if (lastlbn < NDADDR && lastlbn < lbn) {
lastlbn = ffs_lblkno(fs, ip->i_size);
if (lastlbn < UFS_NDADDR && lastlbn < lbn) {
nb = lastlbn;
osize = blksize(fs, ip, nb);
osize = ffs_blksize(fs, ip, nb);
if (osize < fs->fs_bsize && osize > 0) {
mutex_enter(&ump->um_lock);
error = ffs_realloccg(ip, nb,
@@ -676,7 +665,7 @@ ffs_balloc_ufs2(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
osize, (int)fs->fs_bsize, cred, bpp, &newb);
if (error)
return (error);
ip->i_size = lblktosize(fs, nb + 1);
ip->i_size = ffs_lblktosize(fs, nb + 1);
ip->i_ffs2_size = ip->i_size;
uvm_vnp_setsize(vp, ip->i_size);
ip->i_ffs2_db[nb] = ufs_rw64(newb, needswap);
@@ -691,12 +680,12 @@ ffs_balloc_ufs2(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
}
/*
* The first NDADDR blocks are direct blocks
* The first UFS_NDADDR blocks are direct blocks
*/
if (lbn < NDADDR) {
if (lbn < UFS_NDADDR) {
nb = ufs_rw64(ip->i_ffs2_db[lbn], needswap);
if (nb != 0 && ip->i_size >= lblktosize(fs, lbn + 1)) {
if (nb != 0 && ip->i_size >= ffs_lblktosize(fs, lbn + 1)) {
/*
* The block is an already-allocated direct block
@@ -709,7 +698,6 @@ ffs_balloc_ufs2(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
error = bread(vp, lbn, fs->fs_bsize, NOCRED,
B_MODIFY, bpp);
if (error) {
brelse(*bpp, 0);
return (error);
}
}
@@ -721,8 +709,8 @@ ffs_balloc_ufs2(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
* Consider need to reallocate a fragment.
*/
osize = fragroundup(fs, blkoff(fs, ip->i_size));
nsize = fragroundup(fs, size);
osize = ffs_fragroundup(fs, ffs_blkoff(fs, ip->i_size));
nsize = ffs_fragroundup(fs, size);
if (nsize <= osize) {
/*
@@ -735,7 +723,6 @@ ffs_balloc_ufs2(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
error = bread(vp, lbn, osize, NOCRED,
B_MODIFY, bpp);
if (error) {
brelse(*bpp, 0);
return (error);
}
}
@@ -761,8 +748,8 @@ ffs_balloc_ufs2(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
* allocate a new block or fragment.
*/
if (ip->i_size < lblktosize(fs, lbn + 1))
nsize = fragroundup(fs, size);
if (ip->i_size < ffs_lblktosize(fs, lbn + 1))
nsize = ffs_fragroundup(fs, size);
else
nsize = fs->fs_bsize;
mutex_enter(&ump->um_lock);
@@ -773,7 +760,7 @@ ffs_balloc_ufs2(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
if (error)
return (error);
if (bpp != NULL) {
error = ffs_getblk(vp, lbn, fsbtodb(fs, newb),
error = ffs_getblk(vp, lbn, FFS_FSBTODB(fs, newb),
nsize, (flags & B_CLRBUF) != 0, bpp);
if (error)
return error;
@@ -809,7 +796,7 @@ ffs_balloc_ufs2(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
goto fail;
nb = newb;
*allocblk++ = nb;
error = ffs_getblk(vp, indirs[1].in_lbn, fsbtodb(fs, nb),
error = ffs_getblk(vp, indirs[1].in_lbn, FFS_FSBTODB(fs, nb),
fs->fs_bsize, true, &bp);
if (error)
goto fail;
@@ -833,7 +820,6 @@ ffs_balloc_ufs2(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
error = bread(vp,
indirs[i].in_lbn, (int)fs->fs_bsize, NOCRED, 0, &bp);
if (error) {
brelse(bp, 0);
goto fail;
}
bap = (int64_t *)bp->b_data;
@@ -865,7 +851,7 @@ ffs_balloc_ufs2(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
}
nb = newb;
*allocblk++ = nb;
error = ffs_getblk(vp, indirs[i].in_lbn, fsbtodb(fs, nb),
error = ffs_getblk(vp, indirs[i].in_lbn, FFS_FSBTODB(fs, nb),
fs->fs_bsize, true, &nbp);
if (error) {
brelse(bp, 0);
@@ -922,7 +908,7 @@ ffs_balloc_ufs2(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
nb = newb;
*allocblk++ = nb;
if (bpp != NULL) {
error = ffs_getblk(vp, lbn, fsbtodb(fs, nb),
error = ffs_getblk(vp, lbn, FFS_FSBTODB(fs, nb),
fs->fs_bsize, (flags & B_CLRBUF) != 0, bpp);
if (error) {
brelse(bp, 0);
@@ -952,11 +938,10 @@ ffs_balloc_ufs2(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
error = bread(vp, lbn, (int)fs->fs_bsize,
NOCRED, B_MODIFY, &nbp);
if (error) {
brelse(nbp, 0);
goto fail;
}
} else {
error = ffs_getblk(vp, lbn, fsbtodb(fs, nb),
error = ffs_getblk(vp, lbn, FFS_FSBTODB(fs, nb),
fs->fs_bsize, true, &nbp);
if (error)
goto fail;
@@ -988,8 +973,8 @@ fail:
fs->fs_bsize, false, &bp) != 0)
continue;
if (bp->b_oflags & BO_DELWRI) {
nb = fsbtodb(fs, cgtod(fs, dtog(fs,
dbtofsb(fs, bp->b_blkno))));
nb = FFS_FSBTODB(fs, cgtod(fs, dtog(fs,
FFS_DBTOFSB(fs, bp->b_blkno))));
bwrite(bp);
if (ffs_getblk(ip->i_devvp, nb, FFS_NOBLK,
fs->fs_cgsize, false, &bp) != 0)
@@ -1019,7 +1004,6 @@ fail:
(int)fs->fs_bsize, NOCRED, 0, &bp);
if (r) {
panic("Could not unwind indirect block, error %d", r);
brelse(bp, 0);
} else {
bap = (int64_t *)bp->b_data;
bap[indirs[unwindidx].in_off] = 0;
+6 -6
View File
@@ -1,4 +1,4 @@
/* $NetBSD: ffs_bswap.c,v 1.35 2011/03/06 17:08:38 bouyer Exp $ */
/* $NetBSD: ffs_bswap.c,v 1.37 2013/06/09 17:55:46 dholland Exp $ */
/*
* Copyright (c) 1998 Manuel Bouyer.
@@ -30,7 +30,7 @@
#endif
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ffs_bswap.c,v 1.35 2011/03/06 17:08:38 bouyer Exp $");
__KERNEL_RCSID(0, "$NetBSD: ffs_bswap.c,v 1.37 2013/06/09 17:55:46 dholland Exp $");
#include <sys/param.h>
#if defined(_KERNEL)
@@ -119,8 +119,8 @@ ffs_dinode1_swap(struct ufs1_dinode *o, struct ufs1_dinode *n)
n->di_mode = bswap16(o->di_mode);
n->di_nlink = bswap16(o->di_nlink);
n->di_u.oldids[0] = bswap16(o->di_u.oldids[0]);
n->di_u.oldids[1] = bswap16(o->di_u.oldids[1]);
n->di_oldids[0] = bswap16(o->di_oldids[0]);
n->di_oldids[1] = bswap16(o->di_oldids[1]);
n->di_size = bswap64(o->di_size);
n->di_atime = bswap32(o->di_atime);
n->di_atimensec = bswap32(o->di_atimensec);
@@ -128,7 +128,7 @@ ffs_dinode1_swap(struct ufs1_dinode *o, struct ufs1_dinode *n)
n->di_mtimensec = bswap32(o->di_mtimensec);
n->di_ctime = bswap32(o->di_ctime);
n->di_ctimensec = bswap32(o->di_ctimensec);
memcpy(n->di_db, o->di_db, (NDADDR + NIADDR) * sizeof(u_int32_t));
memcpy(n->di_db, o->di_db, (UFS_NDADDR + UFS_NIADDR) * sizeof(u_int32_t));
n->di_flags = bswap32(o->di_flags);
n->di_blocks = bswap32(o->di_blocks);
n->di_gen = bswap32(o->di_gen);
@@ -158,7 +158,7 @@ ffs_dinode2_swap(struct ufs2_dinode *o, struct ufs2_dinode *n)
n->di_kernflags = bswap32(o->di_kernflags);
n->di_flags = bswap32(o->di_flags);
n->di_extsize = bswap32(o->di_extsize);
memcpy(n->di_extb, o->di_extb, (NXADDR + NDADDR + NIADDR) * 8);
memcpy(n->di_extb, o->di_extb, (UFS_NXADDR + UFS_NDADDR + UFS_NIADDR) * 8);
}
void
+4 -2
View File
@@ -1,4 +1,4 @@
/* $NetBSD: ffs_extern.h,v 1.78 2011/06/17 14:23:52 manu Exp $ */
/* $NetBSD: ffs_extern.h,v 1.80 2013/06/16 13:33:30 hannken Exp $ */
/*-
* Copyright (c) 1991, 1993, 1994
@@ -98,6 +98,8 @@ daddr_t ffs_blkpref_ufs2(struct inode *, daddr_t, int, int, int64_t *);
int ffs_blkalloc(struct inode *, daddr_t, long);
int ffs_blkalloc_ump(struct ufsmount *, daddr_t, long);
void ffs_blkfree(struct fs *, struct vnode *, daddr_t, long, ino_t);
void *ffs_discard_init(struct vnode *, struct fs *);
void ffs_discard_finish(void *, int);
void ffs_blkfree_snap(struct fs *, struct vnode *, daddr_t, long, ino_t);
int ffs_vfree(struct vnode *, ino_t, int);
int ffs_checkfreefile(struct fs *, struct vnode *, ino_t);
@@ -151,7 +153,7 @@ void ffs_snapremove(struct vnode *);
int ffs_snapshot(struct mount *, struct vnode *, struct timespec *);
void ffs_snapshot_mount(struct mount *);
void ffs_snapshot_unmount(struct mount *);
void ffs_snapgone(struct inode *);
void ffs_snapgone(struct vnode *);
int ffs_snapshot_read(struct vnode *, struct uio *, int);
/* Write Ahead Physical Block Logging */
+50 -51
View File
@@ -1,4 +1,4 @@
/* $NetBSD: ffs_inode.c,v 1.108 2011/11/23 19:42:10 bouyer Exp $ */
/* $NetBSD: ffs_inode.c,v 1.116 2013/10/20 00:29:10 htodd Exp $ */
/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -61,7 +61,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ffs_inode.c,v 1.108 2011/11/23 19:42:10 bouyer Exp $");
__KERNEL_RCSID(0, "$NetBSD: ffs_inode.c,v 1.116 2013/10/20 00:29:10 htodd Exp $");
#if defined(_KERNEL_OPT)
#include "opt_ffs.h"
@@ -75,7 +75,7 @@ __KERNEL_RCSID(0, "$NetBSD: ffs_inode.c,v 1.108 2011/11/23 19:42:10 bouyer Exp $
#include <sys/fstrans.h>
#include <sys/kauth.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/kmem.h>
#include <sys/mount.h>
#include <sys/proc.h>
#include <sys/resourcevar.h>
@@ -148,15 +148,16 @@ ffs_update(struct vnode *vp, const struct timespec *acc,
ip->i_ffs1_ogid = ip->i_gid; /* XXX */
} /* XXX */
error = bread(ip->i_devvp,
fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
FFS_FSBTODB(fs, ino_to_fsba(fs, ip->i_number)),
(int)fs->fs_bsize, NOCRED, B_MODIFY, &bp);
if (error) {
brelse(bp, 0);
return (error);
}
ip->i_flag &= ~(IN_MODIFIED | IN_ACCESSED);
/* Keep unlinked inode list up to date */
KDASSERT(DIP(ip, nlink) == ip->i_nlink);
KDASSERTMSG(DIP(ip, nlink) == ip->i_nlink,
"DIP(ip, nlink) [%d] == ip->i_nlink [%d]",
DIP(ip, nlink), ip->i_nlink);
if (ip->i_mode) {
if (ip->i_nlink > 0) {
UFS_WAPBL_UNREGISTER_INODE(ip->i_ump->um_mountp,
@@ -207,8 +208,8 @@ ffs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
{
daddr_t lastblock;
struct inode *oip = VTOI(ovp);
daddr_t bn, lastiblock[NIADDR], indir_lbn[NIADDR];
daddr_t blks[NDADDR + NIADDR];
daddr_t bn, lastiblock[UFS_NIADDR], indir_lbn[UFS_NIADDR];
daddr_t blks[UFS_NDADDR + UFS_NIADDR];
struct fs *fs;
int offset, pgoffset, level;
int64_t count, blocksreleased = 0;
@@ -260,12 +261,12 @@ ffs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
*/
if (osize < length) {
if (lblkno(fs, osize) < NDADDR &&
lblkno(fs, osize) != lblkno(fs, length) &&
blkroundup(fs, osize) != osize) {
if (ffs_lblkno(fs, osize) < UFS_NDADDR &&
ffs_lblkno(fs, osize) != ffs_lblkno(fs, length) &&
ffs_blkroundup(fs, osize) != osize) {
off_t eob;
eob = blkroundup(fs, osize);
eob = ffs_blkroundup(fs, osize);
uvm_vnp_setwritesize(ovp, eob);
error = ufs_balloc_range(ovp, osize, eob - osize,
cred, aflag);
@@ -306,7 +307,7 @@ ffs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
* zeroed page past EOF, but that's life.
*/
offset = blkoff(fs, length);
offset = ffs_blkoff(fs, length);
pgoffset = length & PAGE_MASK;
if (ovp->v_type == VREG && (pgoffset != 0 || offset != 0) &&
osize > length) {
@@ -320,9 +321,9 @@ ffs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
if (error)
return error;
}
lbn = lblkno(fs, length);
size = blksize(fs, oip, lbn);
eoz = MIN(MAX(lblktosize(fs, lbn) + size, round_page(pgoffset)),
lbn = ffs_lblkno(fs, length);
size = ffs_blksize(fs, oip, lbn);
eoz = MIN(MAX(ffs_lblktosize(fs, lbn) + size, round_page(pgoffset)),
osize);
ubc_zerorange(&ovp->v_uobj, length, eoz - length,
UBC_UNMAP_FLAG(ovp));
@@ -347,10 +348,10 @@ ffs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
* which we want to keep. Lastblock is -1 when
* the file is truncated to 0.
*/
lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1;
lastiblock[SINGLE] = lastblock - NDADDR;
lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
lastblock = ffs_lblkno(fs, length + fs->fs_bsize - 1) - 1;
lastiblock[SINGLE] = lastblock - UFS_NDADDR;
lastiblock[DOUBLE] = lastiblock[SINGLE] - FFS_NINDIR(fs);
lastiblock[TRIPLE] = lastiblock[DOUBLE] - FFS_NINDIR(fs) * FFS_NINDIR(fs);
nblocks = btodb(fs->fs_bsize);
/*
* Update file and block pointers on disk before we start freeing
@@ -360,14 +361,14 @@ ffs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
*/
sync = 0;
for (level = TRIPLE; level >= SINGLE; level--) {
blks[NDADDR + level] = DIP(oip, ib[level]);
if (lastiblock[level] < 0 && blks[NDADDR + level] != 0) {
blks[UFS_NDADDR + level] = DIP(oip, ib[level]);
if (lastiblock[level] < 0 && blks[UFS_NDADDR + level] != 0) {
sync = 1;
DIP_ASSIGN(oip, ib[level], 0);
lastiblock[level] = -1;
}
}
for (i = 0; i < NDADDR; i++) {
for (i = 0; i < UFS_NDADDR; i++) {
blks[i] = DIP(oip, db[i]);
if (i > lastblock && blks[i] != 0) {
sync = 1;
@@ -387,15 +388,15 @@ ffs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
* Note that we save the new block configuration so we can check it
* when we are done.
*/
for (i = 0; i < NDADDR; i++) {
for (i = 0; i < UFS_NDADDR; i++) {
bn = DIP(oip, db[i]);
DIP_ASSIGN(oip, db[i], blks[i]);
blks[i] = bn;
}
for (i = 0; i < NIADDR; i++) {
for (i = 0; i < UFS_NIADDR; i++) {
bn = DIP(oip, ib[i]);
DIP_ASSIGN(oip, ib[i], blks[NDADDR + i]);
blks[NDADDR + i] = bn;
DIP_ASSIGN(oip, ib[i], blks[UFS_NDADDR + i]);
blks[UFS_NDADDR + i] = bn;
}
oip->i_size = osize;
@@ -407,9 +408,9 @@ ffs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
/*
* Indirect blocks first.
*/
indir_lbn[SINGLE] = -NDADDR;
indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) - 1;
indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1;
indir_lbn[SINGLE] = -UFS_NDADDR;
indir_lbn[DOUBLE] = indir_lbn[SINGLE] - FFS_NINDIR(fs) - 1;
indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - FFS_NINDIR(fs) * FFS_NINDIR(fs) - 1;
for (level = TRIPLE; level >= SINGLE; level--) {
if (oip->i_ump->um_fstype == UFS1)
bn = ufs_rw32(oip->i_ffs1_ib[level],UFS_FSNEEDSWAP(fs));
@@ -417,7 +418,7 @@ ffs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
bn = ufs_rw64(oip->i_ffs2_ib[level],UFS_FSNEEDSWAP(fs));
if (bn != 0) {
error = ffs_indirtrunc(oip, indir_lbn[level],
fsbtodb(fs, bn), lastiblock[level], level, &count);
FFS_FSBTODB(fs, bn), lastiblock[level], level, &count);
if (error)
allerror = error;
blocksreleased += count;
@@ -426,7 +427,7 @@ ffs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
if (oip->i_ump->um_mountp->mnt_wapbl) {
UFS_WAPBL_REGISTER_DEALLOCATION(
oip->i_ump->um_mountp,
fsbtodb(fs, bn), fs->fs_bsize);
FFS_FSBTODB(fs, bn), fs->fs_bsize);
} else
ffs_blkfree(fs, oip->i_devvp, bn,
fs->fs_bsize, oip->i_number);
@@ -440,7 +441,7 @@ ffs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
/*
* All whole direct blocks or frags.
*/
for (i = NDADDR - 1; i > lastblock; i--) {
for (i = UFS_NDADDR - 1; i > lastblock; i--) {
long bsize;
if (oip->i_ump->um_fstype == UFS1)
@@ -450,11 +451,11 @@ ffs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
if (bn == 0)
continue;
DIP_ASSIGN(oip, db[i], 0);
bsize = blksize(fs, oip, i);
bsize = ffs_blksize(fs, oip, i);
if ((oip->i_ump->um_mountp->mnt_wapbl) &&
(ovp->v_type != VREG)) {
UFS_WAPBL_REGISTER_DEALLOCATION(oip->i_ump->um_mountp,
fsbtodb(fs, bn), bsize);
FFS_FSBTODB(fs, bn), bsize);
} else
ffs_blkfree(fs, oip->i_devvp, bn, bsize, oip->i_number);
blocksreleased += btodb(bsize);
@@ -477,10 +478,10 @@ ffs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
* Calculate amount of space we're giving
* back as old block size minus new block size.
*/
oldspace = blksize(fs, oip, lastblock);
oldspace = ffs_blksize(fs, oip, lastblock);
oip->i_size = length;
DIP_ASSIGN(oip, size, length);
newspace = blksize(fs, oip, lastblock);
newspace = ffs_blksize(fs, oip, lastblock);
if (newspace == 0)
panic("itrunc: newspace");
if (oldspace - newspace > 0) {
@@ -489,11 +490,11 @@ ffs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
* the old block # plus the number of frags
* required for the storage we're keeping.
*/
bn += numfrags(fs, newspace);
bn += ffs_numfrags(fs, newspace);
if ((oip->i_ump->um_mountp->mnt_wapbl) &&
(ovp->v_type != VREG)) {
UFS_WAPBL_REGISTER_DEALLOCATION(
oip->i_ump->um_mountp, fsbtodb(fs, bn),
oip->i_ump->um_mountp, FFS_FSBTODB(fs, bn),
oldspace - newspace);
} else
ffs_blkfree(fs, oip->i_devvp, bn,
@@ -505,9 +506,9 @@ ffs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
done:
#ifdef DIAGNOSTIC
for (level = SINGLE; level <= TRIPLE; level++)
if (blks[NDADDR + level] != DIP(oip, ib[level]))
if (blks[UFS_NDADDR + level] != DIP(oip, ib[level]))
panic("itrunc1");
for (i = 0; i < NDADDR; i++)
for (i = 0; i < UFS_NDADDR; i++)
if (blks[i] != DIP(oip, db[i]))
panic("itrunc2");
if (length == 0 &&
@@ -554,9 +555,7 @@ ffs_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn, daddr_t lastbn,
int64_t blkcount, factor, blocksreleased = 0;
int nblocks;
int error = 0, allerror = 0;
#ifdef FFS_EI
const int needswap = UFS_FSNEEDSWAP(fs);
#endif
#define RBAP(ip, i) (((ip)->i_ump->um_fstype == UFS1) ? \
ufs_rw32(bap1[i], needswap) : ufs_rw64(bap2[i], needswap))
#define BAP_ASSIGN(ip, i, value) \
@@ -574,7 +573,7 @@ ffs_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn, daddr_t lastbn,
*/
factor = 1;
for (i = SINGLE; i < level; i++)
factor *= NINDIR(fs);
factor *= FFS_NINDIR(fs);
last = lastbn;
if (lastbn > 0)
last /= factor;
@@ -621,9 +620,9 @@ ffs_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn, daddr_t lastbn,
else
bap2 = (int64_t *)bp->b_data;
if (lastbn >= 0) {
copy = malloc(fs->fs_bsize, M_TEMP, M_WAITOK);
copy = kmem_alloc(fs->fs_bsize, KM_SLEEP);
memcpy((void *)copy, bp->b_data, (u_int)fs->fs_bsize);
for (i = last + 1; i < NINDIR(fs); i++)
for (i = last + 1; i < FFS_NINDIR(fs); i++)
BAP_ASSIGN(ip, i, 0);
error = bwrite(bp);
if (error)
@@ -637,13 +636,13 @@ ffs_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn, daddr_t lastbn,
/*
* Recursively free totally unused blocks.
*/
for (i = NINDIR(fs) - 1, nlbn = lbn + 1 - i * factor; i > last;
for (i = FFS_NINDIR(fs) - 1, nlbn = lbn + 1 - i * factor; i > last;
i--, nlbn += factor) {
nb = RBAP(ip, i);
if (nb == 0)
continue;
if (level > SINGLE) {
error = ffs_indirtrunc(ip, nlbn, fsbtodb(fs, nb),
error = ffs_indirtrunc(ip, nlbn, FFS_FSBTODB(fs, nb),
(daddr_t)-1, level - 1,
&blkcount);
if (error)
@@ -653,7 +652,7 @@ ffs_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn, daddr_t lastbn,
if ((ip->i_ump->um_mountp->mnt_wapbl) &&
((level > SINGLE) || (ITOV(ip)->v_type != VREG))) {
UFS_WAPBL_REGISTER_DEALLOCATION(ip->i_ump->um_mountp,
fsbtodb(fs, nb), fs->fs_bsize);
FFS_FSBTODB(fs, nb), fs->fs_bsize);
} else
ffs_blkfree(fs, ip->i_devvp, nb, fs->fs_bsize,
ip->i_number);
@@ -667,7 +666,7 @@ ffs_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn, daddr_t lastbn,
last = lastbn % factor;
nb = RBAP(ip, i);
if (nb != 0) {
error = ffs_indirtrunc(ip, nlbn, fsbtodb(fs, nb),
error = ffs_indirtrunc(ip, nlbn, FFS_FSBTODB(fs, nb),
last, level - 1, &blkcount);
if (error)
allerror = error;
@@ -676,7 +675,7 @@ ffs_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn, daddr_t lastbn,
}
if (copy != NULL) {
free(copy, M_TEMP);
kmem_free(copy, fs->fs_bsize);
} else {
brelse(bp, BC_INVAL);
}
+119 -125
View File
@@ -1,4 +1,4 @@
/* $NetBSD: ffs_snapshot.c,v 1.118 2011/10/07 09:35:06 hannken Exp $ */
/* $NetBSD: ffs_snapshot.c,v 1.131 2013/10/19 19:28:13 martin Exp $ */
/*
* Copyright 2000 Marshall Kirk McKusick. All Rights Reserved.
@@ -38,7 +38,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ffs_snapshot.c,v 1.118 2011/10/07 09:35:06 hannken Exp $");
__KERNEL_RCSID(0, "$NetBSD: ffs_snapshot.c,v 1.131 2013/10/19 19:28:13 martin Exp $");
#if defined(_KERNEL_OPT)
#include "opt_ffs.h"
@@ -124,7 +124,6 @@ static inline bool is_active_snapshot(struct snap_info *, struct inode *);
static inline daddr_t db_get(struct inode *, int);
static inline void db_assign(struct inode *, int, daddr_t);
static inline daddr_t ib_get(struct inode *, int);
static inline void ib_assign(struct inode *, int, daddr_t);
static inline daddr_t idb_get(struct inode *, void *, int);
static inline void idb_assign(struct inode *, void *, int, daddr_t);
@@ -268,7 +267,7 @@ ffs_snapshot(struct mount *mp, struct vnode *vp, struct timespec *ctime)
* Create a copy of the superblock and its summary information.
*/
error = snapshot_copyfs(mp, vp, &sbbuf);
copy_fs = (struct fs *)((char *)sbbuf + blkoff(fs, fs->fs_sblockloc));
copy_fs = (struct fs *)((char *)sbbuf + ffs_blkoff(fs, fs->fs_sblockloc));
if (error)
goto out;
/*
@@ -345,11 +344,17 @@ ffs_snapshot(struct mount *mp, struct vnode *vp, struct timespec *ctime)
KASSERT(LIST_FIRST(&vp->v_dirtyblkhd) == NULL);
for (bp = LIST_FIRST(&vp->v_cleanblkhd); bp; bp = nbp) {
nbp = LIST_NEXT(bp, b_vnbufs);
KASSERT((bp->b_cflags & BC_BUSY) == 0);
if (bp->b_bcount < fs->fs_bsize) {
bp->b_cflags |= BC_BUSY;
brelsel(bp, BC_INVAL | BC_VFLUSH);
if (bp->b_bcount == fs->fs_bsize)
continue;
error = bbusy(bp, false, 0, NULL);
if (error != 0) {
if (error == EPASSTHROUGH) {
nbp = LIST_FIRST(&vp->v_cleanblkhd);
continue;
}
break;
}
brelsel(bp, BC_INVAL | BC_VFLUSH);
}
mutex_exit(&bufcache_lock);
@@ -424,9 +429,9 @@ snapshot_setup(struct mount *mp, struct vnode *vp)
return EXDEV;
if (vp->v_usecount != 1 || vp->v_writecount != 0)
return EBUSY;
if (kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
NULL) != 0 &&
VTOI(vp)->i_uid != kauth_cred_geteuid(l->l_cred))
error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_SNAPSHOT,
0, mp, vp, NULL);
if (error)
return EACCES;
if (vp->v_size != 0) {
@@ -458,7 +463,7 @@ snapshot_setup(struct mount *mp, struct vnode *vp)
blkno = 1;
blkno = ufs_rw64(blkno, UFS_FSNEEDSWAP(fs));
error = vn_rdwr(UIO_WRITE, vp,
(void *)&blkno, sizeof(blkno), lblktosize(fs, (off_t)numblks),
(void *)&blkno, sizeof(blkno), ffs_lblktosize(fs, (off_t)numblks),
UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, l->l_cred, NULL, NULL);
if (error)
return error;
@@ -476,8 +481,8 @@ snapshot_setup(struct mount *mp, struct vnode *vp)
error = UFS_WAPBL_BEGIN(mp);
if (error)
return error;
for (blkno = NDADDR, n = 0; blkno < numblks; blkno += NINDIR(fs)) {
error = ffs_balloc(vp, lblktosize(fs, (off_t)blkno),
for (blkno = UFS_NDADDR, n = 0; blkno < numblks; blkno += FFS_NINDIR(fs)) {
error = ffs_balloc(vp, ffs_lblktosize(fs, (off_t)blkno),
fs->fs_bsize, l->l_cred, B_METAONLY, &ibp);
if (error)
goto out;
@@ -497,10 +502,10 @@ snapshot_setup(struct mount *mp, struct vnode *vp)
if (error)
goto out;
bawrite(nbp);
blkno = fragstoblks(fs, fs->fs_csaddr);
blkno = ffs_fragstoblks(fs, fs->fs_csaddr);
len = howmany(fs->fs_cssize, fs->fs_bsize);
for (loc = 0; loc < len; loc++) {
error = ffs_balloc(vp, lblktosize(fs, (off_t)(blkno + loc)),
error = ffs_balloc(vp, ffs_lblktosize(fs, (off_t)(blkno + loc)),
fs->fs_bsize, l->l_cred, 0, &nbp);
if (error)
goto out;
@@ -516,7 +521,7 @@ snapshot_setup(struct mount *mp, struct vnode *vp)
* Allocate all cylinder group blocks.
*/
for (cg = 0; cg < fs->fs_ncg; cg++) {
error = ffs_balloc(vp, lfragtosize(fs, cgtod(fs, cg)),
error = ffs_balloc(vp, ffs_lfragtosize(fs, cgtod(fs, cg)),
fs->fs_bsize, l->l_cred, 0, &nbp);
if (error)
goto out;
@@ -554,7 +559,7 @@ snapshot_copyfs(struct mount *mp, struct vnode *vp, void **sbbuf)
* We delay writing it until the suspension is released below.
*/
*sbbuf = malloc(fs->fs_bsize, M_UFSMNT, M_WAITOK);
loc = blkoff(fs, fs->fs_sblockloc);
loc = ffs_blkoff(fs, fs->fs_sblockloc);
if (loc > 0)
memset(*sbbuf, 0, loc);
copyfs = (struct fs *)((char *)(*sbbuf) + loc);
@@ -563,7 +568,7 @@ snapshot_copyfs(struct mount *mp, struct vnode *vp, void **sbbuf)
if (fs->fs_sbsize < size)
memset((char *)(*sbbuf) + loc + fs->fs_sbsize, 0,
size - fs->fs_sbsize);
size = blkroundup(fs, fs->fs_cssize);
size = ffs_blkroundup(fs, fs->fs_cssize);
if (fs->fs_contigsumsize > 0)
size += fs->fs_ncg * sizeof(int32_t);
space = malloc(size, M_UFSMNT, M_WAITOK);
@@ -574,9 +579,8 @@ snapshot_copyfs(struct mount *mp, struct vnode *vp, void **sbbuf)
i = fs->fs_frag - loc % fs->fs_frag;
len = (i == fs->fs_frag) ? 0 : i * fs->fs_fsize;
if (len > 0) {
if ((error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + loc),
if ((error = bread(devvp, FFS_FSBTODB(fs, fs->fs_csaddr + loc),
len, l->l_cred, 0, &bp)) != 0) {
brelse(bp, 0);
free(copyfs->fs_csp, M_UFSMNT);
free(*sbbuf, M_UFSMNT);
*sbbuf = NULL;
@@ -683,8 +687,8 @@ snapshot_expunge(struct mount *mp, struct vnode *vp, struct fs *copy_fs,
*/
blkno = 0;
loc = howmany(xp->i_size, fs->fs_bsize) - 1;
if (loc < NDADDR) {
len = fragroundup(fs, blkoff(fs, xp->i_size));
if (loc < UFS_NDADDR) {
len = ffs_fragroundup(fs, ffs_blkoff(fs, xp->i_size));
if (len > 0 && len < fs->fs_bsize) {
error = UFS_WAPBL_BEGIN(mp);
if (error) {
@@ -722,18 +726,18 @@ snapshot_expunge(struct mount *mp, struct vnode *vp, struct fs *copy_fs,
*/
*snaplist = malloc(*snaplistsize * sizeof(daddr_t), M_UFSMNT, M_WAITOK);
blkp = &(*snaplist)[1];
*blkp++ = lblkno(fs, fs->fs_sblockloc);
blkno = fragstoblks(fs, fs->fs_csaddr);
*blkp++ = ffs_lblkno(fs, fs->fs_sblockloc);
blkno = ffs_fragstoblks(fs, fs->fs_csaddr);
for (cg = 0; cg < fs->fs_ncg; cg++) {
if (fragstoblks(fs, cgtod(fs, cg)) > blkno)
if (ffs_fragstoblks(fs, cgtod(fs, cg)) > blkno)
break;
*blkp++ = fragstoblks(fs, cgtod(fs, cg));
*blkp++ = ffs_fragstoblks(fs, cgtod(fs, cg));
}
len = howmany(fs->fs_cssize, fs->fs_bsize);
for (loc = 0; loc < len; loc++)
*blkp++ = blkno + loc;
for (; cg < fs->fs_ncg; cg++)
*blkp++ = fragstoblks(fs, cgtod(fs, cg));
*blkp++ = ffs_fragstoblks(fs, cgtod(fs, cg));
(*snaplist)[0] = blkp - &(*snaplist)[0];
out:
@@ -808,7 +812,7 @@ snapshot_expunge_snap(struct mount *mp, struct vnode *vp,
for (i = 0; i < snaplistsize; i++)
snaplist[i] = ufs_rw64(snaplist[i], UFS_FSNEEDSWAP(fs));
error = vn_rdwr(UIO_WRITE, vp, (void *)snaplist,
snaplistsize * sizeof(daddr_t), lblktosize(fs, (off_t)numblks),
snaplistsize * sizeof(daddr_t), ffs_lblktosize(fs, (off_t)numblks),
UIO_SYSSPACE, IO_NODELOCKED | IO_UNIT, l->l_cred, NULL, NULL);
for (i = 0; i < snaplistsize; i++)
snaplist[i] = ufs_rw64(snaplist[i], UFS_FSNEEDSWAP(fs));
@@ -822,7 +826,7 @@ out:
/*
* Write the superblock and its summary information to the snapshot.
* Make sure, the first NDADDR blocks get copied to the snapshot.
* Make sure, the first UFS_NDADDR blocks get copied to the snapshot.
*/
static int
snapshot_writefs(struct mount *mp, struct vnode *vp, void *sbbuf)
@@ -835,13 +839,13 @@ snapshot_writefs(struct mount *mp, struct vnode *vp, void *sbbuf)
struct inode *ip = VTOI(vp);
struct lwp *l = curlwp;
copyfs = (struct fs *)((char *)sbbuf + blkoff(fs, fs->fs_sblockloc));
copyfs = (struct fs *)((char *)sbbuf + ffs_blkoff(fs, fs->fs_sblockloc));
/*
* Write the superblock and its summary information
* to the snapshot.
*/
blkno = fragstoblks(fs, fs->fs_csaddr);
blkno = ffs_fragstoblks(fs, fs->fs_csaddr);
len = howmany(fs->fs_cssize, fs->fs_bsize);
space = copyfs->fs_csp;
#ifdef FFS_EI
@@ -857,7 +861,6 @@ snapshot_writefs(struct mount *mp, struct vnode *vp, void *sbbuf)
error = bread(vp, blkno + loc, fs->fs_bsize, l->l_cred,
B_MODIFY, &bp);
if (error) {
brelse(bp, 0);
break;
}
memcpy(bp->b_data, space, fs->fs_bsize);
@@ -866,23 +869,23 @@ snapshot_writefs(struct mount *mp, struct vnode *vp, void *sbbuf)
}
if (error)
goto out;
error = bread(vp, lblkno(fs, fs->fs_sblockloc),
error = bread(vp, ffs_lblkno(fs, fs->fs_sblockloc),
fs->fs_bsize, l->l_cred, B_MODIFY, &bp);
if (error) {
brelse(bp, 0);
goto out;
} else {
memcpy(bp->b_data, sbbuf, fs->fs_bsize);
bawrite(bp);
}
/*
* Copy the first NDADDR blocks to the snapshot so ffs_copyonwrite()
* and ffs_snapblkfree() will always work on indirect blocks.
* Copy the first UFS_NDADDR blocks to the snapshot so
* ffs_copyonwrite() and ffs_snapblkfree() will always work on
* indirect blocks.
*/
for (loc = 0; loc < NDADDR; loc++) {
for (loc = 0; loc < UFS_NDADDR; loc++) {
if (db_get(ip, loc) != 0)
continue;
error = ffs_balloc(vp, lblktosize(fs, (off_t)loc),
error = ffs_balloc(vp, ffs_lblktosize(fs, (off_t)loc),
fs->fs_bsize, l->l_cred, 0, &bp);
if (error)
break;
@@ -923,7 +926,7 @@ cgaccount(struct vnode *vp, int passno, int *redo)
error = UFS_WAPBL_BEGIN(vp->v_mount);
if (error)
return error;
error = ffs_balloc(vp, lfragtosize(fs, cgtod(fs, cg)),
error = ffs_balloc(vp, ffs_lfragtosize(fs, cgtod(fs, cg)),
fs->fs_bsize, curlwp->l_cred, 0, &nbp);
if (error) {
UFS_WAPBL_END(vp->v_mount);
@@ -955,15 +958,14 @@ cgaccount1(int cg, struct vnode *vp, void *data, int passno)
struct fs *fs;
struct lwp *l = curlwp;
daddr_t base, numblks;
int error, len, loc, ns, indiroff;
int error, len, loc, ns __unused, indiroff;
ip = VTOI(vp);
fs = ip->i_fs;
ns = UFS_FSNEEDSWAP(fs);
error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
error = bread(ip->i_devvp, FFS_FSBTODB(fs, cgtod(fs, cg)),
(int)fs->fs_cgsize, l->l_cred, 0, &bp);
if (error) {
brelse(bp, 0);
return (error);
}
cgp = (struct cg *)bp->b_data;
@@ -984,8 +986,8 @@ cgaccount1(int cg, struct vnode *vp, void *data, int passno)
if (base + len >= numblks)
len = numblks - base - 1;
loc = 0;
if (base < NDADDR) {
for ( ; loc < NDADDR; loc++) {
if (base < UFS_NDADDR) {
for ( ; loc < UFS_NDADDR; loc++) {
if (ffs_isblock(fs, cg_blksfree(cgp, ns), loc))
db_assign(ip, loc, BLK_NOCOPY);
else if (db_get(ip, loc) == BLK_NOCOPY) {
@@ -996,15 +998,15 @@ cgaccount1(int cg, struct vnode *vp, void *data, int passno)
}
}
}
if ((error = ffs_balloc(vp, lblktosize(fs, (off_t)(base + loc)),
if ((error = ffs_balloc(vp, ffs_lblktosize(fs, (off_t)(base + loc)),
fs->fs_bsize, l->l_cred, B_METAONLY, &ibp)) != 0)
return (error);
indiroff = (base + loc - NDADDR) % NINDIR(fs);
indiroff = (base + loc - UFS_NDADDR) % FFS_NINDIR(fs);
for ( ; loc < len; loc++, indiroff++) {
if (indiroff >= NINDIR(fs)) {
if (indiroff >= FFS_NINDIR(fs)) {
bawrite(ibp);
if ((error = ffs_balloc(vp,
lblktosize(fs, (off_t)(base + loc)),
ffs_lblktosize(fs, (off_t)(base + loc)),
fs->fs_bsize, l->l_cred, B_METAONLY, &ibp)) != 0)
return (error);
indiroff = 0;
@@ -1033,7 +1035,7 @@ static int
expunge(struct vnode *snapvp, struct inode *cancelip, struct fs *fs,
acctfunc_t acctfunc, int expungetype)
{
int i, error, ns;
int i, error, ns __unused;
daddr_t lbn, rlbn;
daddr_t len, blkno, numblks, blksperindir;
struct ufs1_dinode *dip1;
@@ -1053,7 +1055,7 @@ expunge(struct vnode *snapvp, struct inode *cancelip, struct fs *fs,
* Prepare to expunge the inode. If its inode block has not
* yet been copied, then allocate and fill the copy.
*/
lbn = fragstoblks(fs, ino_to_fsba(fs, cancelip->i_number));
lbn = ffs_fragstoblks(fs, ino_to_fsba(fs, cancelip->i_number));
error = snapblkaddr(snapvp, lbn, &blkno);
if (error)
return error;
@@ -1061,7 +1063,7 @@ expunge(struct vnode *snapvp, struct inode *cancelip, struct fs *fs,
error = bread(snapvp, lbn, fs->fs_bsize, l->l_cred,
B_MODIFY, &bp);
} else {
error = ffs_balloc(snapvp, lblktosize(fs, (off_t)lbn),
error = ffs_balloc(snapvp, ffs_lblktosize(fs, (off_t)lbn),
fs->fs_bsize, l->l_cred, 0, &bp);
if (! error)
error = rwfsblk(snapvp, B_READ, bp->b_data, lbn);
@@ -1086,7 +1088,7 @@ expunge(struct vnode *snapvp, struct inode *cancelip, struct fs *fs,
dip1->di_mode = 0;
dip1->di_size = 0;
dip1->di_blocks = 0;
memset(&dip1->di_db[0], 0, (NDADDR + NIADDR) * sizeof(int32_t));
memset(&dip1->di_db[0], 0, (UFS_NDADDR + UFS_NIADDR) * sizeof(int32_t));
} else {
dip2 = (struct ufs2_dinode *)bp->b_data +
ino_to_fsbo(fs, cancelip->i_number);
@@ -1099,7 +1101,7 @@ expunge(struct vnode *snapvp, struct inode *cancelip, struct fs *fs,
dip2->di_mode = 0;
dip2->di_size = 0;
dip2->di_blocks = 0;
memset(&dip2->di_db[0], 0, (NDADDR + NIADDR) * sizeof(int64_t));
memset(&dip2->di_db[0], 0, (UFS_NDADDR + UFS_NIADDR) * sizeof(int64_t));
}
bdwrite(bp);
UFS_WAPBL_END(mp);
@@ -1112,27 +1114,27 @@ expunge(struct vnode *snapvp, struct inode *cancelip, struct fs *fs,
bap = &cancelip->i_ffs1_db[0];
else
bap = &cancelip->i_ffs2_db[0];
error = (*acctfunc)(snapvp, bap, 0, NDADDR, fs, 0, expungetype);
error = (*acctfunc)(snapvp, bap, 0, UFS_NDADDR, fs, 0, expungetype);
if (error)
return (error);
if (fs->fs_magic == FS_UFS1_MAGIC)
bap = &cancelip->i_ffs1_ib[0];
else
bap = &cancelip->i_ffs2_ib[0];
error = (*acctfunc)(snapvp, bap, 0, NIADDR, fs, -1, expungetype);
error = (*acctfunc)(snapvp, bap, 0, UFS_NIADDR, fs, -1, expungetype);
if (error)
return (error);
blksperindir = 1;
lbn = -NDADDR;
len = numblks - NDADDR;
rlbn = NDADDR;
for (i = 0; len > 0 && i < NIADDR; i++) {
lbn = -UFS_NDADDR;
len = numblks - UFS_NDADDR;
rlbn = UFS_NDADDR;
for (i = 0; len > 0 && i < UFS_NIADDR; i++) {
error = indiracct(snapvp, ITOV(cancelip), i,
ib_get(cancelip, i), lbn, rlbn, len,
blksperindir, fs, acctfunc, expungetype);
if (error)
return (error);
blksperindir *= NINDIR(fs);
blksperindir *= FFS_NINDIR(fs);
lbn -= blksperindir + 1;
len -= blksperindir;
rlbn += blksperindir;
@@ -1151,7 +1153,7 @@ indiracct(struct vnode *snapvp, struct vnode *cancelvp, int level,
{
int error, num, i;
daddr_t subblksperindir;
struct indir indirs[NIADDR + 2];
struct indir indirs[UFS_NIADDR + 2];
daddr_t last;
void *bap;
struct buf *bp;
@@ -1169,12 +1171,12 @@ indiracct(struct vnode *snapvp, struct vnode *cancelvp, int level,
* We have to expand bread here since it will deadlock looking
* up the block number for any blocks that are not in the cache.
*/
error = ffs_getblk(cancelvp, lbn, fsbtodb(fs, blkno), fs->fs_bsize,
error = ffs_getblk(cancelvp, lbn, FFS_FSBTODB(fs, blkno), fs->fs_bsize,
false, &bp);
if (error)
return error;
if ((bp->b_oflags & (BO_DONE | BO_DELWRI)) == 0 && (error =
rwfsblk(bp->b_vp, B_READ, bp->b_data, fragstoblks(fs, blkno)))) {
rwfsblk(bp->b_vp, B_READ, bp->b_data, ffs_fragstoblks(fs, blkno)))) {
brelse(bp, 0);
return (error);
}
@@ -1182,8 +1184,8 @@ indiracct(struct vnode *snapvp, struct vnode *cancelvp, int level,
* Account for the block pointers in this indirect block.
*/
last = howmany(remblks, blksperindir);
if (last > NINDIR(fs))
last = NINDIR(fs);
if (last > FFS_NINDIR(fs))
last = FFS_NINDIR(fs);
bap = malloc(fs->fs_bsize, M_DEVBUF, M_WAITOK | M_ZERO);
memcpy((void *)bap, bp->b_data, fs->fs_bsize);
brelse(bp, 0);
@@ -1195,7 +1197,7 @@ indiracct(struct vnode *snapvp, struct vnode *cancelvp, int level,
* Account for the block pointers in each of the indirect blocks
* in the levels below us.
*/
subblksperindir = blksperindir / NINDIR(fs);
subblksperindir = blksperindir / FFS_NINDIR(fs);
for (lbn++, level--, i = 0; i < last; i++) {
error = indiracct(snapvp, cancelvp, level,
idb_get(VTOI(snapvp), bap, i), lbn, rlbn, remblks,
@@ -1250,17 +1252,17 @@ snapacct(struct vnode *vp, void *bap, int oldblkp, int lastblkp,
blkno = idb_get(ip, bap, oldblkp);
if (blkno == 0 || blkno == BLK_NOCOPY || blkno == BLK_SNAP)
continue;
lbn = fragstoblks(fs, blkno);
if (lbn < NDADDR) {
lbn = ffs_fragstoblks(fs, blkno);
if (lbn < UFS_NDADDR) {
blkno = db_get(ip, lbn);
ip->i_flag |= IN_CHANGE | IN_UPDATE;
} else {
error = ffs_balloc(vp, lblktosize(fs, (off_t)lbn),
error = ffs_balloc(vp, ffs_lblktosize(fs, (off_t)lbn),
fs->fs_bsize, l->l_cred, B_METAONLY, &ibp);
if (error)
break;
blkno = idb_get(ip, ibp->b_data,
(lbn - NDADDR) % NINDIR(fs));
(lbn - UFS_NDADDR) % FFS_NINDIR(fs));
}
/*
* If we are expunging a snapshot vnode and we
@@ -1269,16 +1271,16 @@ snapacct(struct vnode *vp, void *bap, int oldblkp, int lastblkp,
* we took our current snapshot and can be ignored.
*/
if (expungetype == BLK_SNAP && blkno == BLK_NOCOPY) {
if (lbn >= NDADDR)
if (lbn >= UFS_NDADDR)
brelse(ibp, 0);
} else {
if (blkno != 0)
panic("snapacct: bad block");
if (lbn < NDADDR)
if (lbn < UFS_NDADDR)
db_assign(ip, lbn, expungetype);
else {
idb_assign(ip, ibp->b_data,
(lbn - NDADDR) % NINDIR(fs), expungetype);
(lbn - UFS_NDADDR) % FFS_NINDIR(fs), expungetype);
bdwrite(ibp);
}
}
@@ -1323,7 +1325,7 @@ mapacct(struct vnode *vp, void *bap, int oldblkp, int lastblkp,
if (acctit && expungetype == BLK_SNAP && blkno != BLK_SNAP)
*ip->i_snapblklist++ = lblkno;
if (blkno == BLK_SNAP)
blkno = blkstofrags(fs, lblkno);
blkno = ffs_blkstofrags(fs, lblkno);
ffs_blkfree_snap(fs, vp, blkno, fs->fs_bsize, inum);
if (wbreak > 0 && (++n % wbreak) == 0) {
UFS_WAPBL_END(mp);
@@ -1369,10 +1371,10 @@ blocks_in_journal(struct fs *fs)
* It will not be freed until the last open reference goes away.
*/
void
ffs_snapgone(struct inode *ip)
ffs_snapgone(struct vnode *vp)
{
struct mount *mp = ip->i_devvp->v_specmountpoint;
struct inode *xp;
struct inode *xp, *ip = VTOI(vp);
struct mount *mp = spec_node_getmountedfs(ip->i_devvp);
struct fs *fs;
struct snap_info *si;
int snaploc;
@@ -1423,7 +1425,7 @@ ffs_snapremove(struct vnode *vp)
struct inode *ip = VTOI(vp), *xp;
struct vnode *devvp = ip->i_devvp;
struct fs *fs = ip->i_fs;
struct mount *mp = devvp->v_specmountpoint;
struct mount *mp = spec_node_getmountedfs(devvp);
struct buf *ibp;
struct snap_info *si;
struct lwp *l = curlwp;
@@ -1468,11 +1470,11 @@ ffs_snapremove(struct vnode *vp)
* Clear all BLK_NOCOPY fields. Pass any block claims to other
* snapshots that want them (see ffs_snapblkfree below).
*/
for (blkno = 1; blkno < NDADDR; blkno++) {
for (blkno = 1; blkno < UFS_NDADDR; blkno++) {
dblk = db_get(ip, blkno);
if (dblk == BLK_NOCOPY || dblk == BLK_SNAP)
db_assign(ip, blkno, 0);
else if ((dblk == blkstofrags(fs, blkno) &&
else if ((dblk == ffs_blkstofrags(fs, blkno) &&
ffs_snapblkfree(fs, ip->i_devvp, dblk, fs->fs_bsize,
ip->i_number))) {
DIP_ADD(ip, blocks, -btodb(fs->fs_bsize));
@@ -1480,20 +1482,20 @@ ffs_snapremove(struct vnode *vp)
}
}
numblks = howmany(ip->i_size, fs->fs_bsize);
for (blkno = NDADDR; blkno < numblks; blkno += NINDIR(fs)) {
error = ffs_balloc(vp, lblktosize(fs, (off_t)blkno),
for (blkno = UFS_NDADDR; blkno < numblks; blkno += FFS_NINDIR(fs)) {
error = ffs_balloc(vp, ffs_lblktosize(fs, (off_t)blkno),
fs->fs_bsize, l->l_cred, B_METAONLY, &ibp);
if (error)
continue;
if (fs->fs_size - blkno > NINDIR(fs))
last = NINDIR(fs);
if (fs->fs_size - blkno > FFS_NINDIR(fs))
last = FFS_NINDIR(fs);
else
last = fs->fs_size - blkno;
for (loc = 0; loc < last; loc++) {
dblk = idb_get(ip, ibp->b_data, loc);
if (dblk == BLK_NOCOPY || dblk == BLK_SNAP)
idb_assign(ip, ibp->b_data, loc, 0);
else if (dblk == blkstofrags(fs, blkno) &&
else if (dblk == ffs_blkstofrags(fs, blkno) &&
ffs_snapblkfree(fs, ip->i_devvp, dblk,
fs->fs_bsize, ip->i_number)) {
DIP_ADD(ip, blocks, -btodb(fs->fs_bsize));
@@ -1539,7 +1541,7 @@ int
ffs_snapblkfree(struct fs *fs, struct vnode *devvp, daddr_t bno,
long size, ino_t inum)
{
struct mount *mp = devvp->v_specmountpoint;
struct mount *mp = spec_node_getmountedfs(devvp);
struct buf *ibp;
struct inode *ip;
struct vnode *vp = NULL;
@@ -1551,7 +1553,7 @@ ffs_snapblkfree(struct fs *fs, struct vnode *devvp, daddr_t bno,
int indiroff = 0, error = 0, claimedblk = 0;
si = VFSTOUFS(mp)->um_snapinfo;
lbn = fragstoblks(fs, bno);
lbn = ffs_fragstoblks(fs, bno);
mutex_enter(&si->si_snaplock);
mutex_enter(&si->si_lock);
si->si_owner = curlwp;
@@ -1563,17 +1565,17 @@ retry:
/*
* Lookup block being written.
*/
if (lbn < NDADDR) {
if (lbn < UFS_NDADDR) {
blkno = db_get(ip, lbn);
} else {
mutex_exit(&si->si_lock);
error = ffs_balloc(vp, lblktosize(fs, (off_t)lbn),
error = ffs_balloc(vp, ffs_lblktosize(fs, (off_t)lbn),
fs->fs_bsize, FSCRED, B_METAONLY, &ibp);
if (error) {
mutex_enter(&si->si_lock);
break;
}
indiroff = (lbn - NDADDR) % NINDIR(fs);
indiroff = (lbn - UFS_NDADDR) % FFS_NINDIR(fs);
blkno = idb_get(ip, ibp->b_data, indiroff);
mutex_enter(&si->si_lock);
if (gen != si->si_gen) {
@@ -1598,7 +1600,7 @@ retry:
*/
if (claimedblk)
panic("snapblkfree: inconsistent block type");
if (lbn < NDADDR) {
if (lbn < UFS_NDADDR) {
db_assign(ip, lbn, BLK_NOCOPY);
ip->i_flag |= IN_CHANGE | IN_UPDATE;
} else {
@@ -1620,7 +1622,7 @@ retry:
* (default), or does not care about the block,
* it is not needed.
*/
if (lbn >= NDADDR)
if (lbn >= UFS_NDADDR)
brelse(ibp, 0);
continue;
}
@@ -1641,7 +1643,7 @@ retry:
lbn, (unsigned long long)inum);
#endif
mutex_exit(&si->si_lock);
if (lbn < NDADDR) {
if (lbn < UFS_NDADDR) {
db_assign(ip, lbn, bno);
} else {
idb_assign(ip, ibp->b_data, indiroff, bno);
@@ -1662,7 +1664,7 @@ retry:
mutex_exit(&si->si_snaplock);
return (error == 0);
}
if (lbn >= NDADDR)
if (lbn >= UFS_NDADDR)
brelse(ibp, 0);
#ifdef DEBUG
if (snapdebug)
@@ -1725,7 +1727,7 @@ ffs_snapshot_mount(struct mount *mp)
struct inode *ip, *xp;
struct snap_info *si;
daddr_t snaplistsize, *snapblklist;
int i, error, ns, snaploc, loc;
int i, error, ns __unused, snaploc, loc;
/*
* No persistent snapshots on apple ufs file systems.
@@ -1776,7 +1778,7 @@ ffs_snapshot_mount(struct mount *mp)
*/
error = vn_rdwr(UIO_READ, vp,
(void *)&snaplistsize, sizeof(snaplistsize),
lblktosize(fs, howmany(fs->fs_size, fs->fs_frag)),
ffs_lblktosize(fs, howmany(fs->fs_size, fs->fs_frag)),
UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT|IO_ALTSEMANTICS,
l->l_cred, NULL, NULL);
if (error) {
@@ -1791,7 +1793,7 @@ ffs_snapshot_mount(struct mount *mp)
else {
error = vn_rdwr(UIO_READ, vp, (void *)snapblklist,
snaplistsize * sizeof(daddr_t),
lblktosize(fs, howmany(fs->fs_size, fs->fs_frag)),
ffs_lblktosize(fs, howmany(fs->fs_size, fs->fs_frag)),
UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT|IO_ALTSEMANTICS,
l->l_cred, NULL, NULL);
for (i = 0; i < snaplistsize; i++)
@@ -1875,7 +1877,7 @@ ffs_copyonwrite(void *v, struct buf *bp, bool data_valid)
struct fs *fs;
struct inode *ip;
struct vnode *devvp = v, *vp = NULL;
struct mount *mp = devvp->v_specmountpoint;
struct mount *mp = spec_node_getmountedfs(devvp);
struct snap_info *si;
void *saved_data = NULL;
daddr_t lbn, blkno, *snapblklist;
@@ -1898,8 +1900,8 @@ ffs_copyonwrite(void *v, struct buf *bp, bool data_valid)
* By doing these checks we avoid several potential deadlocks.
*/
fs = ip->i_fs;
lbn = fragstoblks(fs, dbtofsb(fs, bp->b_blkno));
if (bp->b_blkno >= fsbtodb(fs, fs->fs_size)) {
lbn = ffs_fragstoblks(fs, FFS_DBTOFSB(fs, bp->b_blkno));
if (bp->b_blkno >= FFS_FSBTODB(fs, fs->fs_size)) {
mutex_exit(&si->si_lock);
return 0;
}
@@ -1962,7 +1964,7 @@ retry:
/*
* Check to see if block needs to be copied.
*/
if (lbn < NDADDR) {
if (lbn < UFS_NDADDR) {
blkno = db_get(ip, lbn);
} else {
mutex_exit(&si->si_lock);
@@ -2074,22 +2076,22 @@ ffs_snapshot_read(struct vnode *vp, struct uio *uio, int ioflag)
if (ioflag & IO_ALTSEMANTICS)
fsbytes = ip->i_size;
else
fsbytes = lfragtosize(fs, fs->fs_size);
fsbytes = ffs_lfragtosize(fs, fs->fs_size);
for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
bytesinfile = fsbytes - uio->uio_offset;
if (bytesinfile <= 0)
break;
lbn = lblkno(fs, uio->uio_offset);
lbn = ffs_lblkno(fs, uio->uio_offset);
nextlbn = lbn + 1;
size = fs->fs_bsize;
blkoffset = blkoff(fs, uio->uio_offset);
blkoffset = ffs_blkoff(fs, uio->uio_offset);
xfersize = MIN(MIN(fs->fs_bsize - blkoffset, uio->uio_resid),
bytesinfile);
if (lblktosize(fs, nextlbn + 1) >= fsbytes) {
if (lblktosize(fs, lbn) + size > fsbytes)
size = fragroundup(fs,
fsbytes - lblktosize(fs, lbn));
if (ffs_lblktosize(fs, nextlbn + 1) >= fsbytes) {
if (ffs_lblktosize(fs, lbn) + size > fsbytes)
size = ffs_fragroundup(fs,
fsbytes - ffs_lblktosize(fs, lbn));
error = bread(vp, lbn, size, NOCRED, 0, &bp);
} else {
int nextsize = fs->fs_bsize;
@@ -2133,7 +2135,7 @@ ffs_snapshot_read(struct vnode *vp, struct uio *uio, int ioflag)
static int
snapblkaddr(struct vnode *vp, daddr_t lbn, daddr_t *res)
{
struct indir indirs[NIADDR + 2];
struct indir indirs[UFS_NIADDR + 2];
struct inode *ip = VTOI(vp);
struct fs *fs = ip->i_fs;
struct buf *bp;
@@ -2141,7 +2143,7 @@ snapblkaddr(struct vnode *vp, daddr_t lbn, daddr_t *res)
KASSERT(lbn >= 0);
if (lbn < NDADDR) {
if (lbn < UFS_NDADDR) {
*res = db_get(ip, lbn);
return 0;
}
@@ -2159,9 +2161,10 @@ snapblkaddr(struct vnode *vp, daddr_t lbn, daddr_t *res)
return error;
}
error = bread(vp, indirs[num-1].in_lbn, fs->fs_bsize, NOCRED, 0, &bp);
if (error == 0)
if (error == 0) {
*res = idb_get(ip, bp->b_data, indirs[num-1].in_off);
brelse(bp, 0);
brelse(bp, 0);
}
return error;
}
@@ -2183,7 +2186,7 @@ rwfsblk(struct vnode *vp, int flags, void *data, daddr_t lbn)
nbp->b_bcount = nbp->b_bufsize = fs->fs_bsize;
nbp->b_error = 0;
nbp->b_data = data;
nbp->b_blkno = nbp->b_rawblkno = fsbtodb(fs, blkstofrags(fs, lbn));
nbp->b_blkno = nbp->b_rawblkno = FFS_FSBTODB(fs, ffs_blkstofrags(fs, lbn));
nbp->b_proc = NULL;
nbp->b_dev = ip->i_devvp->v_rdev;
SET(nbp->b_cflags, BC_BUSY); /* mark buffer busy */
@@ -2219,7 +2222,7 @@ syncsnap(struct vnode *vp)
KASSERT(bp->b_bcount == fs->fs_bsize);
mutex_exit(&bufcache_lock);
error = rwfsblk(vp, B_WRITE, bp->b_data,
fragstoblks(fs, dbtofsb(fs, bp->b_blkno)));
ffs_fragstoblks(fs, FFS_DBTOFSB(fs, bp->b_blkno)));
brelse(bp, BC_INVAL | BC_VFLUSH);
if (error)
return error;
@@ -2241,7 +2244,7 @@ wrsnapblk(struct vnode *vp, void *data, daddr_t lbn)
struct buf *bp;
int error;
error = ffs_balloc(vp, lblktosize(fs, (off_t)lbn), fs->fs_bsize,
error = ffs_balloc(vp, ffs_lblktosize(fs, (off_t)lbn), fs->fs_bsize,
FSCRED, (ip->i_nlink > 0 ? B_SYNC : 0), &bp);
if (error)
return error;
@@ -2303,15 +2306,6 @@ ib_get(struct inode *ip, int loc)
return ufs_rw64(ip->i_ffs2_ib[loc], UFS_IPNEEDSWAP(ip));
}
static inline void
ib_assign(struct inode *ip, int loc, daddr_t val)
{
if (ip->i_ump->um_fstype == UFS1)
ip->i_ffs1_ib[loc] = ufs_rw32(val, UFS_IPNEEDSWAP(ip));
else
ip->i_ffs2_ib[loc] = ufs_rw64(val, UFS_IPNEEDSWAP(ip));
}
static inline daddr_t
idb_get(struct inode *ip, void *bf, int loc)
{
+2 -4
View File
@@ -1,4 +1,4 @@
/* $NetBSD: ffs_subr.c,v 1.47 2011/08/14 12:37:09 christos Exp $ */
/* $NetBSD: ffs_subr.c,v 1.48 2013/10/20 00:29:10 htodd Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@@ -36,7 +36,7 @@
#endif
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ffs_subr.c,v 1.47 2011/08/14 12:37:09 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: ffs_subr.c,v 1.48 2013/10/20 00:29:10 htodd Exp $");
#include <sys/param.h>
@@ -286,9 +286,7 @@ ffs_clusteracct(struct fs *fs, struct cg *cgp, int32_t blkno, int cnt)
int32_t *lp;
u_char *freemapp, *mapp;
int i, start, end, forw, back, map, bit;
#ifdef FFS_EI
const int needswap = UFS_FSNEEDSWAP(fs);
#endif
/* KASSERT(mutex_owned(&ump->um_lock)); */
+105 -65
View File
@@ -1,4 +1,4 @@
/* $NetBSD: ffs_vfsops.c,v 1.271 2011/11/14 18:35:14 hannken Exp $ */
/* $NetBSD: ffs_vfsops.c,v 1.291 2013/11/23 13:35:37 christos Exp $ */
/*-
* Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -61,7 +61,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.271 2011/11/14 18:35:14 hannken Exp $");
__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.291 2013/11/23 13:35:37 christos Exp $");
#if defined(_KERNEL_OPT)
#include "opt_ffs.h"
@@ -85,7 +85,7 @@ __KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.271 2011/11/14 18:35:14 hannken Exp
#include <sys/disklabel.h>
#include <sys/ioctl.h>
#include <sys/errno.h>
#include <sys/malloc.h>
#include <sys/kmem.h>
#include <sys/pool.h>
#include <sys/lock.h>
#include <sys/sysctl.h>
@@ -115,6 +115,8 @@ static int ffs_vfs_fsync(vnode_t *, int);
static struct sysctllog *ffs_sysctl_log;
static kauth_listener_t ffs_snapshot_listener;
/* how many times ffs_init() was called */
int ffs_initcount = 0;
@@ -171,9 +173,25 @@ static const struct ufs_ops ffs_ufsops = {
.uo_valloc = ffs_valloc,
.uo_vfree = ffs_vfree,
.uo_balloc = ffs_balloc,
.uo_unmark_vnode = (void (*)(vnode_t *))nullop,
.uo_snapgone = ffs_snapgone,
};
static int
ffs_snapshot_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
void *arg0, void *arg1, void *arg2, void *arg3)
{
vnode_t *vp = arg2;
int result = KAUTH_RESULT_DEFER;;
if (action != KAUTH_SYSTEM_FS_SNAPSHOT)
return result;
if (VTOI(vp)->i_uid == kauth_cred_geteuid(cred))
result = KAUTH_RESULT_ALLOW;
return result;
}
static int
ffs_modcmd(modcmd_t cmd, void *arg)
{
@@ -247,12 +265,19 @@ ffs_modcmd(modcmd_t cmd, void *arg)
#endif /* UFS_EXTATTR */
ffs_snapshot_listener = kauth_listen_scope(KAUTH_SCOPE_SYSTEM,
ffs_snapshot_cb, NULL);
if (ffs_snapshot_listener == NULL)
printf("ffs_modcmd: can't listen on system scope.\n");
break;
case MODULE_CMD_FINI:
error = vfs_detach(&ffs_vfsops);
if (error != 0)
break;
sysctl_teardown(&ffs_sysctl_log);
if (ffs_snapshot_listener != NULL)
kauth_unlisten_scope(ffs_snapshot_listener);
break;
default:
error = ENOTTY;
@@ -300,9 +325,7 @@ ffs_mountroot(void)
return (error);
}
mp->mnt_flag &= ~MNT_FORCE;
mutex_enter(&mountlist_lock);
CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
mutex_exit(&mountlist_lock);
mountlist_append(mp);
ump = VFSTOUFS(mp);
fs = ump->um_fs;
memset(fs->fs_fsmnt, 0, sizeof(fs->fs_fsmnt));
@@ -404,7 +427,9 @@ ffs_mount(struct mount *mp, const char *path, void *data, size_t *data_len)
(mp->mnt_flag & MNT_RDONLY) == 0)
accessmode |= VWRITE;
vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
error = genfs_can_mount(devvp, accessmode, l->l_cred);
error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
KAUTH_REQ_SYSTEM_MOUNT_DEVICE, mp, devvp,
KAUTH_ARG(accessmode));
VOP_UNLOCK(devvp);
}
@@ -524,7 +549,7 @@ ffs_mount(struct mount *mp, const char *path, void *data, size_t *data_len)
#ifdef WAPBL
if (fs->fs_flags & FS_DOWAPBL) {
printf("%s: replaying log to disk\n",
fs->fs_fsmnt);
mp->mnt_stat.f_mntonname);
KDASSERT(mp->mnt_wapbl_replay);
error = wapbl_replay_write(mp->mnt_wapbl_replay,
devvp);
@@ -553,6 +578,10 @@ ffs_mount(struct mount *mp, const char *path, void *data, size_t *data_len)
}
}
#endif
if ((mp->mnt_flag & MNT_DISCARD) && !(ump->um_discarddata))
ump->um_discarddata = ffs_discard_init(devvp, fs);
if (args->fspec == NULL)
return 0;
}
@@ -645,10 +674,9 @@ ffs_reload(struct mount *mp, kauth_cred_t cred, struct lwp *l)
error = bread(devvp, fs->fs_sblockloc / DEV_BSIZE, fs->fs_sbsize,
NOCRED, 0, &bp);
if (error) {
brelse(bp, 0);
return (error);
}
newfs = malloc(fs->fs_sbsize, M_UFSMNT, M_WAITOK);
newfs = kmem_alloc(fs->fs_sbsize, KM_SLEEP);
memcpy(newfs, bp->b_data, fs->fs_sbsize);
#ifdef FFS_EI
if (ump->um_flags & UFS_NEEDSWAP) {
@@ -662,7 +690,7 @@ ffs_reload(struct mount *mp, kauth_cred_t cred, struct lwp *l)
newfs->fs_bsize > MAXBSIZE ||
newfs->fs_bsize < sizeof(struct fs)) {
brelse(bp, 0);
free(newfs, M_UFSMNT);
kmem_free(newfs, fs->fs_sbsize);
return (EIO); /* XXX needs translation */
}
/* Store off old fs_sblockloc for fs_oldfscompat_read. */
@@ -679,7 +707,7 @@ ffs_reload(struct mount *mp, kauth_cred_t cred, struct lwp *l)
newfs->fs_active = fs->fs_active;
memcpy(fs, newfs, (u_int)fs->fs_sbsize);
brelse(bp, 0);
free(newfs, M_UFSMNT);
kmem_free(newfs, fs->fs_sbsize);
/* Recheck for apple UFS filesystem */
ump->um_flags &= ~UFS_ISAPPLEUFS;
@@ -700,7 +728,6 @@ ffs_reload(struct mount *mp, kauth_cred_t cred, struct lwp *l)
error = bread(devvp, (daddr_t)(APPLEUFS_LABEL_OFFSET / DEV_BSIZE),
APPLEUFS_LABEL_SIZE, cred, 0, &bp);
if (error && error != EINVAL) {
brelse(bp, 0);
return (error);
}
if (error == 0) {
@@ -708,8 +735,8 @@ ffs_reload(struct mount *mp, kauth_cred_t cred, struct lwp *l)
(struct appleufslabel *)bp->b_data, NULL);
if (error == 0)
ump->um_flags |= UFS_ISAPPLEUFS;
brelse(bp, 0);
}
brelse(bp, 0);
bp = NULL;
}
#else
@@ -724,7 +751,7 @@ ffs_reload(struct mount *mp, kauth_cred_t cred, struct lwp *l)
mp->mnt_iflag |= IMNT_DTYPE;
} else {
ump->um_maxsymlinklen = fs->fs_maxsymlinklen;
ump->um_dirblksiz = DIRBLKSIZ;
ump->um_dirblksiz = UFS_DIRBLKSIZ;
if (ump->um_maxsymlinklen > 0)
mp->mnt_iflag |= IMNT_DTYPE;
else
@@ -759,10 +786,9 @@ ffs_reload(struct mount *mp, kauth_cred_t cred, struct lwp *l)
bsize = fs->fs_bsize;
if (i + fs->fs_frag > blks)
bsize = (blks - i) * fs->fs_fsize;
error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), bsize,
error = bread(devvp, FFS_FSBTODB(fs, fs->fs_csaddr + i), bsize,
NOCRED, 0, &bp);
if (error) {
brelse(bp, 0);
return (error);
}
#ifdef FFS_EI
@@ -775,8 +801,6 @@ ffs_reload(struct mount *mp, kauth_cred_t cred, struct lwp *l)
space = (char *)space + bsize;
brelse(bp, 0);
}
if (fs->fs_snapinum[0] != 0)
ffs_snapshot_mount(mp);
/*
* We no longer know anything about clusters per cylinder group.
*/
@@ -801,7 +825,7 @@ ffs_reload(struct mount *mp, kauth_cred_t cred, struct lwp *l)
/*
* Step 4: invalidate all inactive vnodes.
*/
if (vrecycle(vp, &mntvnode_lock, l)) {
if (vrecycle(vp, &mntvnode_lock)) {
mutex_enter(&mntvnode_lock);
(void)vunmark(mvp);
goto loop;
@@ -821,10 +845,9 @@ ffs_reload(struct mount *mp, kauth_cred_t cred, struct lwp *l)
* Step 6: re-read inode data for all active vnodes.
*/
ip = VTOI(vp);
error = bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
error = bread(devvp, FFS_FSBTODB(fs, ino_to_fsba(fs, ip->i_number)),
(int)fs->fs_bsize, NOCRED, 0, &bp);
if (error) {
brelse(bp, 0);
vput(vp);
(void)vunmark(mvp);
break;
@@ -865,6 +888,7 @@ ffs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l)
int32_t *lp;
kauth_cred_t cred;
u_int32_t sbsize = 8192; /* keep gcc happy*/
u_int32_t allocsbsize;
int32_t fsbsize;
dev = devvp->v_rdev;
@@ -889,8 +913,7 @@ ffs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l)
if (error)
return error;
ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
memset(ump, 0, sizeof *ump);
ump = kmem_zalloc(sizeof(*ump), KM_SLEEP);
mutex_init(&ump->um_lock, MUTEX_DEFAULT, IPL_NONE);
error = ffs_snapshot_init(ump);
if (error)
@@ -927,7 +950,7 @@ ffs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l)
fsbsize = fs->fs_bsize;
#ifdef FFS_EI
needswap = 0;
} else if (fs->fs_magic == bswap32(FS_UFS1_MAGIC)) {
} else if (fs->fs_magic == FS_UFS1_MAGIC_SWAPPED) {
sbsize = bswap32(fs->fs_sbsize);
fstype = UFS1;
fsbsize = bswap32(fs->fs_bsize);
@@ -939,7 +962,7 @@ ffs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l)
fsbsize = fs->fs_bsize;
#ifdef FFS_EI
needswap = 0;
} else if (fs->fs_magic == bswap32(FS_UFS2_MAGIC)) {
} else if (fs->fs_magic == FS_UFS2_MAGIC_SWAPPED) {
sbsize = bswap32(fs->fs_sbsize);
fstype = UFS2;
fsbsize = bswap32(fs->fs_bsize);
@@ -986,7 +1009,7 @@ ffs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l)
break;
}
fs = malloc((u_long)sbsize, M_UFSMNT, M_WAITOK);
fs = kmem_alloc((u_long)sbsize, KM_SLEEP);
memcpy(fs, bp->b_data, sbsize);
ump->um_fs = fs;
@@ -1023,7 +1046,7 @@ ffs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l)
/* Force a re-read of the superblock */
brelse(bp, BC_INVAL);
bp = NULL;
free(fs, M_UFSMNT);
kmem_free(fs, sbsize);
fs = NULL;
goto sbagain;
}
@@ -1126,7 +1149,7 @@ ffs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l)
*/
if (!ronly) {
error = bread(devvp, fsbtodb(fs, fs->fs_size - 1), fs->fs_fsize,
error = bread(devvp, FFS_FSBTODB(fs, fs->fs_size - 1), fs->fs_fsize,
cred, 0, &bp);
if (bp->b_bcount != fs->fs_fsize)
error = EINVAL;
@@ -1150,16 +1173,17 @@ ffs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l)
if (fs->fs_contigsumsize > 0)
bsize += fs->fs_ncg * sizeof(int32_t);
bsize += fs->fs_ncg * sizeof(*fs->fs_contigdirs);
space = malloc((u_long)bsize, M_UFSMNT, M_WAITOK);
allocsbsize = bsize;
space = kmem_alloc((u_long)allocsbsize, KM_SLEEP);
fs->fs_csp = space;
for (i = 0; i < blks; i += fs->fs_frag) {
bsize = fs->fs_bsize;
if (i + fs->fs_frag > blks)
bsize = (blks - i) * fs->fs_fsize;
error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), bsize,
error = bread(devvp, FFS_FSBTODB(fs, fs->fs_csaddr + i), bsize,
cred, 0, &bp);
if (error) {
free(fs->fs_csp, M_UFSMNT);
kmem_free(fs->fs_csp, allocsbsize);
goto out;
}
#ifdef FFS_EI
@@ -1206,7 +1230,7 @@ ffs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l)
mp->mnt_iflag |= IMNT_DTYPE;
} else {
ump->um_maxsymlinklen = fs->fs_maxsymlinklen;
ump->um_dirblksiz = DIRBLKSIZ;
ump->um_dirblksiz = UFS_DIRBLKSIZ;
if (ump->um_maxsymlinklen > 0)
mp->mnt_iflag |= IMNT_DTYPE;
else
@@ -1229,7 +1253,7 @@ ffs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l)
ump->um_seqinc = fs->fs_frag;
for (i = 0; i < MAXQUOTAS; i++)
ump->um_quotas[i] = NULLVP;
devvp->v_specmountpoint = mp;
spec_node_setmountedfs(devvp, mp);
if (ronly == 0 && fs->fs_snapinum[0] != 0)
ffs_snapshot_mount(mp);
#ifdef WAPBL
@@ -1243,7 +1267,7 @@ ffs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l)
error = ffs_wapbl_start(mp);
if (error) {
free(fs->fs_csp, M_UFSMNT);
kmem_free(fs->fs_csp, allocsbsize);
goto out;
}
}
@@ -1252,7 +1276,7 @@ ffs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l)
#ifdef QUOTA2
error = ffs_quota2_mount(mp);
if (error) {
free(fs->fs_csp, M_UFSMNT);
kmem_free(fs->fs_csp, allocsbsize);
goto out;
}
#else
@@ -1263,7 +1287,7 @@ ffs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l)
(mp->mnt_flag & MNT_FORCE) ? "" : ", not mounting");
if ((mp->mnt_flag & MNT_FORCE) == 0) {
error = EINVAL;
free(fs->fs_csp, M_UFSMNT);
kmem_free(fs->fs_csp, allocsbsize);
goto out;
}
}
@@ -1278,6 +1302,9 @@ ffs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l)
ufs_extattr_uepm_init(&ump->um_extattr);
#endif /* UFS_EXTATTR */
if (mp->mnt_flag & MNT_DISCARD)
ump->um_discarddata = ffs_discard_init(devvp, fs);
return (0);
out:
#ifdef WAPBL
@@ -1290,15 +1317,15 @@ out:
fstrans_unmount(mp);
if (fs)
free(fs, M_UFSMNT);
devvp->v_specmountpoint = NULL;
kmem_free(fs, fs->fs_sbsize);
spec_node_setmountedfs(devvp, NULL);
if (bp)
brelse(bp, bset);
if (ump) {
if (ump->um_oldfscompat)
free(ump->um_oldfscompat, M_UFSMNT);
kmem_free(ump->um_oldfscompat, 512 + 3*sizeof(int32_t));
mutex_destroy(&ump->um_lock);
free(ump, M_UFSMNT);
kmem_free(ump, sizeof(*ump));
mp->mnt_data = NULL;
}
return (error);
@@ -1322,8 +1349,8 @@ ffs_oldfscompat_read(struct fs *fs, struct ufsmount *ump, daddr_t sblockloc)
return;
if (!ump->um_oldfscompat)
ump->um_oldfscompat = malloc(512 + 3*sizeof(int32_t),
M_UFSMNT, M_WAITOK);
ump->um_oldfscompat = kmem_alloc(512 + 3*sizeof(int32_t),
KM_SLEEP);
memcpy(ump->um_oldfscompat, &fs->fs_old_postbl_start, 512);
extrasave = ump->um_oldfscompat;
@@ -1429,10 +1456,16 @@ ffs_unmount(struct mount *mp, int mntflags)
struct ufsmount *ump = VFSTOUFS(mp);
struct fs *fs = ump->um_fs;
int error, flags;
u_int32_t bsize;
#ifdef WAPBL
extern int doforce;
#endif
if (ump->um_discarddata) {
ffs_discard_finish(ump->um_discarddata, mntflags);
ump->um_discarddata = NULL;
}
flags = 0;
if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
@@ -1462,26 +1495,26 @@ ffs_unmount(struct mount *mp, int mntflags)
return error;
}
#endif /* WAPBL */
#ifdef UFS_EXTATTR
if (ump->um_fstype == UFS1) {
ufs_extattr_stop(mp, l);
ufs_extattr_uepm_destroy(&ump->um_extattr);
}
#endif /* UFS_EXTATTR */
if (ump->um_devvp->v_type != VBAD)
ump->um_devvp->v_specmountpoint = NULL;
spec_node_setmountedfs(ump->um_devvp, NULL);
vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY);
(void)VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD | FWRITE,
NOCRED);
vput(ump->um_devvp);
free(fs->fs_csp, M_UFSMNT);
free(fs, M_UFSMNT);
bsize = fs->fs_cssize;
if (fs->fs_contigsumsize > 0)
bsize += fs->fs_ncg * sizeof(int32_t);
bsize += fs->fs_ncg * sizeof(*fs->fs_contigdirs);
kmem_free(fs->fs_csp, bsize);
kmem_free(fs, fs->fs_sbsize);
if (ump->um_oldfscompat != NULL)
free(ump->um_oldfscompat, M_UFSMNT);
kmem_free(ump->um_oldfscompat, 512 + 3*sizeof(int32_t));
mutex_destroy(&ump->um_lock);
ffs_snapshot_fini(ump);
free(ump, M_UFSMNT);
kmem_free(ump, sizeof(*ump));
mp->mnt_data = NULL;
mp->mnt_flag &= ~MNT_LOCAL;
fstrans_unmount(mp);
@@ -1508,6 +1541,14 @@ ffs_flushfiles(struct mount *mp, int flags, struct lwp *l)
#ifdef QUOTA2
if ((error = quota2_umount(mp, flags)) != 0)
return (error);
#endif
#ifdef UFS_EXTATTR
if (ump->um_fstype == UFS1) {
if (ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)
ufs_extattr_stop(mp, l);
if (ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_INITIALIZED)
ufs_extattr_uepm_destroy(&ump->um_extattr);
}
#endif
if ((error = vflush(mp, 0, SKIPSYSTEM | flags)) != 0)
return (error);
@@ -1556,15 +1597,15 @@ ffs_statvfs(struct mount *mp, struct statvfs *sbp)
sbp->f_frsize = fs->fs_fsize;
sbp->f_iosize = fs->fs_bsize;
sbp->f_blocks = fs->fs_dsize;
sbp->f_bfree = blkstofrags(fs, fs->fs_cstotal.cs_nbfree) +
fs->fs_cstotal.cs_nffree + dbtofsb(fs, fs->fs_pendingblocks);
sbp->f_bfree = ffs_blkstofrags(fs, fs->fs_cstotal.cs_nbfree) +
fs->fs_cstotal.cs_nffree + FFS_DBTOFSB(fs, fs->fs_pendingblocks);
sbp->f_bresvd = ((u_int64_t) fs->fs_dsize * (u_int64_t)
fs->fs_minfree) / (u_int64_t) 100;
if (sbp->f_bfree > sbp->f_bresvd)
sbp->f_bavail = sbp->f_bfree - sbp->f_bresvd;
else
sbp->f_bavail = 0;
sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO;
sbp->f_files = fs->fs_ncg * fs->fs_ipg - UFS_ROOTINO;
sbp->f_ffree = fs->fs_cstotal.cs_nifree + fs->fs_pendinginodes;
sbp->f_favail = sbp->f_ffree;
sbp->f_fresvd = 0;
@@ -1818,7 +1859,7 @@ ffs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
mutex_exit(&ufs_hashlock);
/* Read in the disk contents for the inode, copy into the inode. */
error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
error = bread(ump->um_devvp, FFS_FSBTODB(fs, ino_to_fsba(fs, ino)),
(int)fs->fs_bsize, NOCRED, 0, &bp);
if (error) {
@@ -1830,7 +1871,6 @@ ffs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
*/
vput(vp);
brelse(bp, 0);
*vpp = NULL;
return (error);
}
@@ -1892,7 +1932,7 @@ ffs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
memcpy(&ufh, fhp, sizeof(ufh));
fs = VFSTOUFS(mp)->um_fs;
if (ufh.ufid_ino < ROOTINO ||
if (ufh.ufid_ino < UFS_ROOTINO ||
ufh.ufid_ino >= fs->fs_ncg * fs->fs_ipg)
return (ESTALE);
return (ufs_fhtovp(mp, &ufh, vpp));
@@ -2007,7 +2047,7 @@ ffs_cgupdate(struct ufsmount *mp, int waitfor)
size = fs->fs_bsize;
if (i + fs->fs_frag > blks)
size = (blks - i) * fs->fs_fsize;
error = ffs_getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i),
error = ffs_getblk(mp->um_devvp, FFS_FSBTODB(fs, fs->fs_csaddr + i),
FFS_NOBLK, size, false, &bp);
if (error)
break;
@@ -2087,7 +2127,7 @@ ffs_vfs_fsync(vnode_t *vp, int flags)
#endif
KASSERT(vp->v_type == VBLK);
KASSERT(vp->v_specmountpoint != NULL);
KASSERT(spec_node_getmountedfs(vp) != NULL);
/*
* Flush all dirty data associated with the vnode.
@@ -2101,7 +2141,7 @@ ffs_vfs_fsync(vnode_t *vp, int flags)
return error;
#ifdef WAPBL
mp = vp->v_specmountpoint;
mp = spec_node_getmountedfs(vp);
if (mp && mp->mnt_wapbl) {
/*
* Don't bother writing out metadata if the syncer is
@@ -2133,7 +2173,7 @@ ffs_vfs_fsync(vnode_t *vp, int flags)
}
#endif /* WAPBL */
error = vflushbuf(vp, (flags & FSYNC_WAIT) != 0);
error = vflushbuf(vp, flags);
if (error == 0 && (flags & FSYNC_CACHE) != 0) {
i = 1;
(void)VOP_IOCTL(vp, DIOCCACHESYNC, &i, FWRITE,
+32 -30
View File
@@ -1,4 +1,4 @@
/* $NetBSD: ffs_vnops.c,v 1.120 2011/06/27 16:34:47 manu Exp $ */
/* $NetBSD: ffs_vnops.c,v 1.123 2013/06/23 07:28:37 dholland Exp $ */
/*-
* Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -61,7 +61,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ffs_vnops.c,v 1.120 2011/06/27 16:34:47 manu Exp $");
__KERNEL_RCSID(0, "$NetBSD: ffs_vnops.c,v 1.123 2013/06/23 07:28:37 dholland Exp $");
#if defined(_KERNEL_OPT)
#include "opt_ffs.h"
@@ -333,7 +333,7 @@ ffs_fsync(void *v)
} */ *ap = v;
struct buf *bp;
int num, error, i;
struct indir ia[NIADDR + 1];
struct indir ia[UFS_NIADDR + 1];
int bsize;
daddr_t blk_high;
struct vnode *vp;
@@ -405,7 +405,7 @@ ffs_fsync(void *v)
* Then, flush indirect blocks.
*/
if (blk_high >= NDADDR) {
if (blk_high >= UFS_NDADDR) {
error = ufs_getlbns(vp, blk_high, ia, &num);
if (error)
goto out;
@@ -455,35 +455,35 @@ int
ffs_full_fsync(struct vnode *vp, int flags)
{
int error, i, uflags;
struct mount *mp;
KASSERT(vp->v_tag == VT_UFS);
KASSERT(VTOI(vp) != NULL);
KASSERT(vp->v_type != VCHR && vp->v_type != VBLK);
error = 0;
uflags = UPDATE_CLOSE | ((flags & FSYNC_WAIT) ? UPDATE_WAIT : 0);
mp = vp->v_mount;
/*
* Flush all dirty data associated with the vnode.
*/
if (vp->v_type == VREG) {
int pflags = PGO_ALLPAGES | PGO_CLEANIT;
if ((flags & FSYNC_WAIT))
pflags |= PGO_SYNCIO;
if (fstrans_getstate(mp) == FSTRANS_SUSPENDING)
pflags |= PGO_FREE;
mutex_enter(vp->v_interlock);
error = VOP_PUTPAGES(vp, 0, 0, pflags);
if (error)
return error;
}
#ifdef WAPBL
struct mount *mp = vp->v_mount;
if (mp && mp->mnt_wapbl) {
/*
* Flush all dirty data associated with the vnode.
*/
if (vp->v_type == VREG) {
int pflags = PGO_ALLPAGES | PGO_CLEANIT;
if ((flags & FSYNC_LAZY))
pflags |= PGO_LAZY;
if ((flags & FSYNC_WAIT))
pflags |= PGO_SYNCIO;
if (fstrans_getstate(mp) == FSTRANS_SUSPENDING)
pflags |= PGO_FREE;
mutex_enter(vp->v_interlock);
error = VOP_PUTPAGES(vp, 0, 0, pflags);
if (error)
return error;
}
/*
* Don't bother writing out metadata if the syncer is
* making the request. We will let the sync vnode
@@ -500,6 +500,8 @@ ffs_full_fsync(struct vnode *vp, int flags)
return error;
error = ffs_update(vp, NULL, NULL, uflags);
UFS_WAPBL_END(mp);
} else {
error = 0;
}
if (error || (flags & FSYNC_NOLOG) != 0)
return error;
@@ -525,7 +527,7 @@ ffs_full_fsync(struct vnode *vp, int flags)
}
#endif /* WAPBL */
error = vflushbuf(vp, (flags & FSYNC_WAIT) != 0);
error = vflushbuf(vp, flags);
if (error == 0)
error = ffs_update(vp, NULL, NULL, uflags);
if (error == 0 && (flags & FSYNC_CACHE) != 0) {
@@ -609,12 +611,12 @@ ffs_gop_size(struct vnode *vp, off_t size, off_t *eobp, int flags)
struct fs *fs = ip->i_fs;
daddr_t olbn, nlbn;
olbn = lblkno(fs, ip->i_size);
nlbn = lblkno(fs, size);
if (nlbn < NDADDR && olbn <= nlbn) {
*eobp = fragroundup(fs, size);
olbn = ffs_lblkno(fs, ip->i_size);
nlbn = ffs_lblkno(fs, size);
if (nlbn < UFS_NDADDR && olbn <= nlbn) {
*eobp = ffs_fragroundup(fs, size);
} else {
*eobp = blkroundup(fs, size);
*eobp = ffs_blkroundup(fs, size);
}
}
+22 -21
View File
@@ -1,4 +1,4 @@
/* $NetBSD: ffs_wapbl.c,v 1.17 2010/12/24 13:38:57 mlelstv Exp $ */
/* $NetBSD: ffs_wapbl.c,v 1.25 2013/10/25 11:35:55 martin Exp $ */
/*-
* Copyright (c) 2003,2006,2008 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ffs_wapbl.c,v 1.17 2010/12/24 13:38:57 mlelstv Exp $");
__KERNEL_RCSID(0, "$NetBSD: ffs_wapbl.c,v 1.25 2013/10/25 11:35:55 martin Exp $");
#define WAPBL_INTERNAL
@@ -165,7 +165,7 @@ ffs_wapbl_sync_metadata(struct mount *mp, daddr_t *deallocblks,
{
struct ufsmount *ump = VFSTOUFS(mp);
struct fs *fs = ump->um_fs;
int i, error;
int i, error __diagused;
#ifdef WAPBL_DEBUG_INODES
ufs_wapbl_verify_inodes(mp, "ffs_wapbl_sync_metadata");
@@ -177,7 +177,7 @@ ffs_wapbl_sync_metadata(struct mount *mp, daddr_t *deallocblks,
* if it cannot read the cylinder group block
*/
ffs_blkfree(fs, ump->um_devvp,
dbtofsb(fs, deallocblks[i]), dealloclens[i], -1);
FFS_DBTOFSB(fs, deallocblks[i]), dealloclens[i], -1);
}
fs->fs_fmod = 0;
@@ -201,7 +201,7 @@ ffs_wapbl_abort_sync_metadata(struct mount *mp, daddr_t *deallocblks,
* blkfree succeeded above, then this shouldn't fail because
* the buffer will be locked in the current transaction.
*/
ffs_blkalloc_ump(ump, dbtofsb(fs, deallocblks[i]),
ffs_blkalloc_ump(ump, FFS_DBTOFSB(fs, deallocblks[i]),
dealloclens[i]);
}
}
@@ -528,7 +528,7 @@ wapbl_log_position(struct mount *mp, struct fs *fs, struct vnode *devvp,
}
desired_logsize =
lfragtosize(fs, fs->fs_size) / UFS_WAPBL_JOURNAL_SCALE;
ffs_lfragtosize(fs, fs->fs_size) / UFS_WAPBL_JOURNAL_SCALE;
DPRINTF("desired log size = %" PRId64 " kB\n", desired_logsize / 1024);
desired_logsize = max(desired_logsize, UFS_WAPBL_MIN_JOURNAL_SIZE);
desired_logsize = min(desired_logsize, UFS_WAPBL_MAX_JOURNAL_SIZE);
@@ -536,7 +536,7 @@ wapbl_log_position(struct mount *mp, struct fs *fs, struct vnode *devvp,
desired_logsize / 1024);
/* Is there space after after filesystem on partition for log? */
logstart = fsbtodb(fs, fs->fs_size);
logstart = FFS_FSBTODB(fs, fs->fs_size);
error = getdisksize(devvp, &numsecs, &secsize);
if (error)
return error;
@@ -680,11 +680,11 @@ wapbl_allocate_log_file(struct mount *mp, struct vnode *vp,
if (addr == 0) {
printf("%s: log not allocated, largest extent is "
"%" PRId64 "MB\n", __func__,
lblktosize(fs, size) / (1024 * 1024));
ffs_lblktosize(fs, size) / (1024 * 1024));
return ENOSPC;
}
logsize = lblktosize(fs, size); /* final log size */
logsize = ffs_lblktosize(fs, size); /* final log size */
VTOI(vp)->i_ffs_first_data_blk = addr;
VTOI(vp)->i_ffs_first_indir_blk = indir_addr;
@@ -695,7 +695,7 @@ wapbl_allocate_log_file(struct mount *mp, struct vnode *vp,
return error;
}
*startp = fsbtodb(fs, addr);
*startp = FFS_FSBTODB(fs, addr);
*countp = btodb(logsize);
*extradatap = VTOI(vp)->i_number;
@@ -731,13 +731,11 @@ wapbl_find_log_start(struct mount *mp, struct vnode *vp, off_t logsize,
daddr_t desired_blks, min_desired_blks;
daddr_t freeblks, best_blks;
int bpcg, cg, error, fixedsize, indir_blks, n, s;
#ifdef FFS_EI
const int needswap = UFS_FSNEEDSWAP(fs);
#endif
if (logsize == 0) {
fixedsize = 0; /* We can adjust the size if tight */
logsize = lfragtosize(fs, fs->fs_dsize) /
logsize = ffs_lfragtosize(fs, fs->fs_dsize) /
UFS_WAPBL_JOURNAL_SCALE;
DPRINTF("suggested log size = %" PRId64 "\n", logsize);
logsize = max(logsize, UFS_WAPBL_MIN_JOURNAL_SIZE);
@@ -753,8 +751,8 @@ wapbl_find_log_start(struct mount *mp, struct vnode *vp, off_t logsize,
/* add in number of indirect blocks needed */
indir_blks = 0;
if (desired_blks >= NDADDR) {
struct indir indirs[NIADDR + 2];
if (desired_blks >= UFS_NDADDR) {
struct indir indirs[UFS_NIADDR + 2];
int num;
error = ufs_getlbns(vp, desired_blks, indirs, &num);
@@ -793,11 +791,11 @@ wapbl_find_log_start(struct mount *mp, struct vnode *vp, off_t logsize,
min_desired_blks = desired_blks / 4;
/* Look at number of blocks per CG. If it's too small, bail early. */
bpcg = fragstoblks(fs, fs->fs_fpg);
bpcg = ffs_fragstoblks(fs, fs->fs_fpg);
if (min_desired_blks > bpcg) {
printf("ffs_wapbl: cylinder group size of %" PRId64 " MB "
" is not big enough for journal\n",
lblktosize(fs, bpcg) / (1024 * 1024));
ffs_lblktosize(fs, bpcg) / (1024 * 1024));
goto bad;
}
@@ -819,10 +817,13 @@ wapbl_find_log_start(struct mount *mp, struct vnode *vp, off_t logsize,
best_blks < desired_blks && cg >= 0 && cg < fs->fs_ncg;
s++, n = -n, cg += n * s) {
DPRINTF("check cg %d of %d\n", cg, fs->fs_ncg);
error = bread(devvp, fsbtodb(fs, cgtod(fs, cg)),
error = bread(devvp, FFS_FSBTODB(fs, cgtod(fs, cg)),
fs->fs_cgsize, FSCRED, 0, &bp);
if (error) {
continue;
}
cgp = (struct cg *)bp->b_data;
if (error || !cg_chkmagic(cgp, UFS_FSNEEDSWAP(fs))) {
if (!cg_chkmagic(cgp, UFS_FSNEEDSWAP(fs))) {
brelse(bp, 0);
continue;
}
@@ -848,7 +849,7 @@ wapbl_find_log_start(struct mount *mp, struct vnode *vp, off_t logsize,
if (freeblks > best_blks) {
best_blks = freeblks;
best_addr = blkstofrags(fs, start_addr) +
best_addr = ffs_blkstofrags(fs, start_addr) +
cgbase(fs, cg);
if (freeblks >= desired_blks) {
@@ -869,7 +870,7 @@ wapbl_find_log_start(struct mount *mp, struct vnode *vp, off_t logsize,
*indir_addr = 0;
} else {
/* put indirect blocks at start, and data blocks after */
*addr = best_addr + blkstofrags(fs, indir_blks);
*addr = best_addr + ffs_blkstofrags(fs, indir_blks);
*indir_addr = best_addr;
}
*size = min(desired_blks, best_blks) - indir_blks;
+41 -38
View File
@@ -1,4 +1,4 @@
/* $NetBSD: fs.h,v 1.56 2011/03/06 17:08:38 bouyer Exp $ */
/* $NetBSD: fs.h,v 1.65 2013/09/03 02:24:01 dholland Exp $ */
/*
* Copyright (c) 1982, 1986, 1993
@@ -123,7 +123,7 @@
* necessary. The file system format retains only a single pointer
* to such a fragment, which is a piece of a single large block that
* has been divided. The size of such a fragment is determinable from
* information in the inode, using the ``blksize(fs, ip, lbn)'' macro.
* information in the inode, using the ``ffs_blksize(fs, ip, lbn)'' macro.
*
* The file system records space availability at the fragment level;
* to determine block availability, aligned fragments are examined.
@@ -287,8 +287,8 @@ struct fs {
int32_t fs_sbsize; /* actual size of super block */
int32_t fs_spare1[2]; /* old fs_csmask */
/* old fs_csshift */
int32_t fs_nindir; /* value of NINDIR */
int32_t fs_inopb; /* value of INOPB */
int32_t fs_nindir; /* value of FFS_NINDIR */
int32_t fs_inopb; /* value of FFS_INOPB */
int32_t fs_old_nspf; /* value of NSPF */
/* yet another configuration parameter */
int32_t fs_optim; /* optimization preference, see below */
@@ -422,13 +422,16 @@ struct fs {
#define FS_UNCLEAN 0x001 /* file system not clean at mount (unused) */
#define FS_DOSOFTDEP 0x002 /* file system using soft dependencies */
#define FS_NEEDSFSCK 0x004 /* needs sync fsck (FreeBSD compat, unused) */
#define FS_INDEXDIRS 0x008 /* kernel supports indexed directories */
#define FS_SUJ 0x008 /* file system using journaled softupdates */
#define FS_ACLS 0x010 /* file system has ACLs enabled */
#define FS_MULTILABEL 0x020 /* file system is MAC multi-label */
#define FS_GJOURNAL 0x40 /* gjournaled file system */
#define FS_FLAGS_UPDATED 0x80 /* flags have been moved to new location */
#define FS_DOWAPBL 0x100 /* Write ahead physical block logging */
/* FS_NFS4ACLS 0x100 file system has NFSv4 ACLs enabled (FBSD) */
#define FS_DOQUOTA2 0x200 /* in-filesystem quotas */
/* FS_INDEXDIRS 0x200 kernel supports indexed directories (FBSD)*/
#define FS_TRIM 0x400 /* discard deleted blocks in storage layer */
/* File system flags that are ok for NetBSD if set in fs_flags */
#define FS_KNOWN_FLAGS (FS_DOSOFTDEP | FS_DOWAPBL | FS_DOQUOTA2)
@@ -470,7 +473,7 @@ struct fs {
/* block map */ howmany((fpg), NBBY) +\
/* if present */ ((fs)->fs_contigsumsize <= 0 ? 0 : \
/* cluster sum */ (fs)->fs_contigsumsize * sizeof(int32_t) + \
/* cluster map */ howmany(fragstoblks(fs, (fpg)), NBBY)))
/* cluster map */ howmany(ffs_fragstoblks(fs, (fpg)), NBBY)))
#define CGSIZE(fs) CGSIZE_IF((fs), (fs)->fs_ipg, (fs)->fs_fpg)
@@ -605,11 +608,11 @@ struct ocg {
* This maps file system blocks to device size blocks.
*/
#if defined (_KERNEL)
#define fsbtodb(fs, b) ((b) << ((fs)->fs_fshift - DEV_BSHIFT))
#define dbtofsb(fs, b) ((b) >> ((fs)->fs_fshift - DEV_BSHIFT))
#define FFS_FSBTODB(fs, b) ((b) << ((fs)->fs_fshift - DEV_BSHIFT))
#define FFS_DBTOFSB(fs, b) ((b) >> ((fs)->fs_fshift - DEV_BSHIFT))
#else
#define fsbtodb(fs, b) ((b) << (fs)->fs_fsbtodb)
#define dbtofsb(fs, b) ((b) >> (fs)->fs_fsbtodb)
#define FFS_FSBTODB(fs, b) ((b) << (fs)->fs_fsbtodb)
#define FFS_DBTOFSB(fs, b) ((b) >> (fs)->fs_fsbtodb)
#endif
/*
@@ -636,8 +639,8 @@ struct ocg {
#define ino_to_cg(fs, x) ((x) / (fs)->fs_ipg)
#define ino_to_fsba(fs, x) \
((daddr_t)(cgimin(fs, ino_to_cg(fs, x)) + \
(blkstofrags((fs), (((x) % (fs)->fs_ipg) / INOPB(fs))))))
#define ino_to_fsbo(fs, x) ((x) % INOPB(fs))
(ffs_blkstofrags((fs), (((x) % (fs)->fs_ipg) / FFS_INOPB(fs))))))
#define ino_to_fsbo(fs, x) ((x) % FFS_INOPB(fs))
/*
* Give cylinder group number for a file system block.
@@ -653,11 +656,11 @@ struct ocg {
#define blkmap(fs, map, loc) \
(((map)[(loc) / NBBY] >> ((loc) % NBBY)) & (0xff >> (NBBY - (fs)->fs_frag)))
#define old_cbtocylno(fs, bno) \
(fsbtodb(fs, bno) / (fs)->fs_old_spc)
(FFS_FSBTODB(fs, bno) / (fs)->fs_old_spc)
#define old_cbtorpos(fs, bno) \
((fs)->fs_old_nrpos <= 1 ? 0 : \
(fsbtodb(fs, bno) % (fs)->fs_old_spc / (fs)->fs_old_nsect * (fs)->fs_old_trackskew + \
fsbtodb(fs, bno) % (fs)->fs_old_spc % (fs)->fs_old_nsect * (fs)->fs_old_interleave) % \
(FFS_FSBTODB(fs, bno) % (fs)->fs_old_spc / (fs)->fs_old_nsect * (fs)->fs_old_trackskew + \
FFS_FSBTODB(fs, bno) % (fs)->fs_old_spc % (fs)->fs_old_nsect * (fs)->fs_old_interleave) % \
(fs)->fs_old_nsect * (fs)->fs_old_nrpos / (fs)->fs_old_npsect)
/*
@@ -665,29 +668,29 @@ struct ocg {
* quantities by using shifts and masks in place of divisions
* modulos and multiplications.
*/
#define blkoff(fs, loc) /* calculates (loc % fs->fs_bsize) */ \
#define ffs_blkoff(fs, loc) /* calculates (loc % fs->fs_bsize) */ \
((loc) & (fs)->fs_qbmask)
#define fragoff(fs, loc) /* calculates (loc % fs->fs_fsize) */ \
#define ffs_fragoff(fs, loc) /* calculates (loc % fs->fs_fsize) */ \
((loc) & (fs)->fs_qfmask)
#define lfragtosize(fs, frag) /* calculates ((off_t)frag * fs->fs_fsize) */ \
#define ffs_lfragtosize(fs, frag) /* calculates ((off_t)frag * fs->fs_fsize) */ \
(((off_t)(frag)) << (fs)->fs_fshift)
#define lblktosize(fs, blk) /* calculates ((off_t)blk * fs->fs_bsize) */ \
(((off_t)(blk)) << (fs)->fs_bshift)
#define lblkno(fs, loc) /* calculates (loc / fs->fs_bsize) */ \
#define ffs_lblktosize(fs, blk) /* calculates ((off_t)blk * fs->fs_bsize) */ \
((uint64_t)(((off_t)(blk)) << (fs)->fs_bshift))
#define ffs_lblkno(fs, loc) /* calculates (loc / fs->fs_bsize) */ \
((loc) >> (fs)->fs_bshift)
#define numfrags(fs, loc) /* calculates (loc / fs->fs_fsize) */ \
#define ffs_numfrags(fs, loc) /* calculates (loc / fs->fs_fsize) */ \
((loc) >> (fs)->fs_fshift)
#define blkroundup(fs, size) /* calculates roundup(size, fs->fs_bsize) */ \
#define ffs_blkroundup(fs, size) /* calculates roundup(size, fs->fs_bsize) */ \
(((size) + (fs)->fs_qbmask) & (fs)->fs_bmask)
#define fragroundup(fs, size) /* calculates roundup(size, fs->fs_fsize) */ \
#define ffs_fragroundup(fs, size) /* calculates roundup(size, fs->fs_fsize) */ \
(((size) + (fs)->fs_qfmask) & (fs)->fs_fmask)
#define fragstoblks(fs, frags) /* calculates (frags / fs->fs_frag) */ \
#define ffs_fragstoblks(fs, frags) /* calculates (frags / fs->fs_frag) */ \
((frags) >> (fs)->fs_fragshift)
#define blkstofrags(fs, blks) /* calculates (blks * fs->fs_frag) */ \
#define ffs_blkstofrags(fs, blks) /* calculates (blks * fs->fs_frag) */ \
((blks) << (fs)->fs_fragshift)
#define fragnum(fs, fsb) /* calculates (fsb % fs->fs_frag) */ \
#define ffs_fragnum(fs, fsb) /* calculates (fsb % fs->fs_frag) */ \
((fsb) & ((fs)->fs_frag - 1))
#define blknum(fs, fsb) /* calculates rounddown(fsb, fs->fs_frag) */ \
#define ffs_blknum(fs, fsb) /* calculates rounddown(fsb, fs->fs_frag) */ \
((fsb) &~ ((fs)->fs_frag - 1))
/*
@@ -695,34 +698,34 @@ struct ocg {
* percentage to hold in reserve.
*/
#define freespace(fs, percentreserved) \
(blkstofrags((fs), (fs)->fs_cstotal.cs_nbfree) + \
(ffs_blkstofrags((fs), (fs)->fs_cstotal.cs_nbfree) + \
(fs)->fs_cstotal.cs_nffree - \
(((off_t)((fs)->fs_dsize)) * (percentreserved) / 100))
/*
* Determining the size of a file block in the file system.
*/
#define blksize(fs, ip, lbn) \
(((lbn) >= NDADDR || (ip)->i_size >= lblktosize(fs, (lbn) + 1)) \
#define ffs_blksize(fs, ip, lbn) \
(((lbn) >= UFS_NDADDR || (ip)->i_size >= ffs_lblktosize(fs, (lbn) + 1)) \
? (fs)->fs_bsize \
: (fragroundup(fs, blkoff(fs, (ip)->i_size))))
: ((int32_t)ffs_fragroundup(fs, ffs_blkoff(fs, (ip)->i_size))))
#define sblksize(fs, size, lbn) \
(((lbn) >= NDADDR || (size) >= ((lbn) + 1) << (fs)->fs_bshift) \
#define ffs_sblksize(fs, size, lbn) \
(((lbn) >= UFS_NDADDR || (size) >= ((lbn) + 1) << (fs)->fs_bshift) \
? (fs)->fs_bsize \
: (fragroundup(fs, blkoff(fs, (size)))))
: ((int32_t)ffs_fragroundup(fs, ffs_blkoff(fs, (uint64_t)(size)))))
/*
* Number of inodes in a secondary storage block/fragment.
*/
#define INOPB(fs) ((fs)->fs_inopb)
#define INOPF(fs) ((fs)->fs_inopb >> (fs)->fs_fragshift)
#define FFS_INOPB(fs) ((fs)->fs_inopb)
#define FFS_INOPF(fs) ((fs)->fs_inopb >> (fs)->fs_fragshift)
/*
* Number of indirects in a file system block.
*/
#define NINDIR(fs) ((fs)->fs_nindir)
#define FFS_NINDIR(fs) ((fs)->fs_nindir)
/*
* Apple UFS Label:
+42 -23
View File
@@ -1,4 +1,4 @@
# $NetBSD: files.ufs,v 1.27 2011/11/24 15:51:31 ahoka Exp $
# $NetBSD: files.ufs,v 1.33 2013/07/20 19:59:31 dholland Exp $
deffs FFS
deffs EXT2FS
@@ -10,7 +10,10 @@ defflag opt_ffs.h FFS_EI FFS_NO_SNAPSHOT APPLE_UFS
UFS_DIRHASH
UFS_EXTATTR UFS_EXTATTR_AUTOSTART
defflag opt_lfs.h LFS_KERNEL_RFW
defflag opt_lfs.h LFS_EI LFS_KERNEL_RFW
LFS_DIRHASH
LFS_EXTATTR LFS_EXTATTR_AUTOSTART
LFS_QUOTA LFS_QUOTA2
file ufs/ext2fs/ext2fs_alloc.c ext2fs
file ufs/ext2fs/ext2fs_balloc.c ext2fs
@@ -19,6 +22,7 @@ file ufs/ext2fs/ext2fs_bswap.c ext2fs
file ufs/ext2fs/ext2fs_inode.c ext2fs
file ufs/ext2fs/ext2fs_lookup.c ext2fs
file ufs/ext2fs/ext2fs_readwrite.c ext2fs
file ufs/ext2fs/ext2fs_rename.c ext2fs
file ufs/ext2fs/ext2fs_subr.c ext2fs
file ufs/ext2fs/ext2fs_vfsops.c ext2fs
file ufs/ext2fs/ext2fs_vnops.c ext2fs
@@ -36,24 +40,23 @@ 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_alloc.c ffs | mfs | ext2fs | chfs
file ufs/ffs/ffs_balloc.c ffs | mfs | ext2fs | chfs
file ufs/ffs/ffs_bswap.c (ffs | mfs) & ffs_ei
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_inode.c ffs | mfs | ext2fs | chfs
file ufs/ffs/ffs_snapshot.c ffs | mfs | ext2fs | chfs
file ufs/ffs/ffs_subr.c ffs | mfs | ext2fs | chfs
file ufs/ffs/ffs_tables.c ffs | mfs | ext2fs | chfs
file ufs/ffs/ffs_vfsops.c ffs | mfs | ext2fs | chfs
file ufs/ffs/ffs_vnops.c ffs | 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 | chfs)
file ufs/ffs/ffs_quota2.c quota2 & (ffs | mfs | ext2fs | chfs)
file ufs/lfs/lfs_alloc.c lfs
file ufs/lfs/lfs_balloc.c lfs
@@ -62,28 +65,44 @@ file ufs/lfs/lfs_cksum.c lfs
file ufs/lfs/lfs_debug.c lfs
file ufs/lfs/lfs_inode.c lfs
file ufs/lfs/lfs_itimes.c lfs
file ufs/lfs/lfs_rename.c lfs
file ufs/lfs/lfs_rfw.c lfs & lfs_kernel_rfw
file ufs/lfs/lfs_segment.c lfs
file ufs/lfs/lfs_subr.c lfs
file ufs/lfs/lfs_syscalls.c lfs
file ufs/lfs/lfs_vfsops.c lfs
file ufs/lfs/lfs_vnops.c lfs
file ufs/lfs/ulfs_bmap.c lfs
file ufs/lfs/ulfs_dirhash.c lfs & lfs_dirhash
file ufs/lfs/ulfs_extattr.c lfs & lfs_extattr
file ufs/lfs/ulfs_ihash.c lfs
file ufs/lfs/ulfs_inode.c lfs
file ufs/lfs/ulfs_lookup.c lfs
file ufs/lfs/ulfs_quota.c lfs & (lfs_quota | lfs_quota2)
file ufs/lfs/ulfs_quota1.c lfs & lfs_quota
file ufs/lfs/ulfs_quota2.c lfs & lfs_quota2
file ufs/lfs/ulfs_quota1_subr.c lfs
file ufs/lfs/ulfs_quota2_subr.c lfs & lfs_quota2
file ufs/lfs/ulfs_snapshot.c lfs
file ufs/lfs/ulfs_vfsops.c lfs
file ufs/lfs/ulfs_vnops.c lfs
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 | chfs
file ufs/ufs/ufs_dirhash.c (ffs | lfs | mfs | ext2fs | chfs) & ufs_dirhash
file ufs/ufs/ufs_bmap.c ffs | mfs | ext2fs | chfs
file ufs/ufs/ufs_dirhash.c (ffs | 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 | 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/ufs_ihash.c ffs | mfs | ext2fs
file ufs/ufs/ufs_inode.c ffs | mfs | ext2fs
file ufs/ufs/ufs_lookup.c ffs | mfs | ext2fs | chfs
file ufs/ufs/ufs_quota.c (quota | quota2) & (ffs | mfs | ext2fs | chfs)
file ufs/ufs/ufs_quota1.c quota & (ffs | mfs | ext2fs | chfs)
file ufs/ufs/ufs_quota2.c quota2 & (ffs | mfs | ext2fs | chfs)
file ufs/ufs/quota1_subr.c
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/quota2_subr.c quota2 & (ffs | mfs | ext2fs | chfs)
file ufs/ufs/ufs_rename.c ffs | mfs | chfs
file ufs/ufs/ufs_vfsops.c ffs | mfs | ext2fs | chfs
file ufs/ufs/ufs_vnops.c ffs | mfs | ext2fs | chfs
file ufs/ufs/ufs_wapbl.c ffs & wapbl
+2 -2
View File
@@ -1,7 +1,7 @@
# $NetBSD: Makefile,v 1.1 1998/06/12 23:23:12 cgd Exp $
# $NetBSD: Makefile,v 1.2 2013/06/08 02:04:31 dholland Exp $
INCSDIR= /usr/include/ufs/lfs
INCS= lfs.h lfs_extern.h
INCS= lfs.h lfs_inode.h lfs_extern.h
.include <bsd.kinc.mk>
+26
View File
@@ -0,0 +1,26 @@
Line counts.
(Part of the premise of splitting lfs from ufs is that in the long run
the size of a standalone lfs will be substantially smaller than the
size of lfs plus the size of ufs. This file is for keeping track of
this proposition.)
As of 20130604 (before the split):
.h .c total
lfs 1467 13858 15325
ufs 2056 12919 14975
As of 20130605 (copied all ufs files verbatim):
lfs-native 1467 13858 15325
lfs-ulfs 2070 12938 15008
lfs-total 3537 26796 30333
A few extra lines appeared copying ufs because I preserved a copy of
the old rcsids.
As of 20130606 (committed the initial split and made things buildable):
lfs-native 1482 13858 15340
lfs-ulfs 1994 13028 15022
lfs-total 3476 26886 30362
+432 -319
View File
@@ -1,4 +1,7 @@
/* $NetBSD: lfs.h,v 1.134 2011/07/11 08:27:40 hannken Exp $ */
/* $NetBSD: lfs.h,v 1.160 2013/07/28 01:22:55 dholland Exp $ */
/* from NetBSD: dinode.h,v 1.22 2013/01/22 09:39:18 dholland Exp */
/* from NetBSD: dir.h,v 1.21 2009/07/22 04:49:19 dholland Exp */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -58,6 +61,89 @@
*
* @(#)lfs.h 8.9 (Berkeley) 5/8/95
*/
/*
* Copyright (c) 2002 Networks Associates Technology, Inc.
* All rights reserved.
*
* This software was developed for the FreeBSD Project by Marshall
* Kirk McKusick and Network Associates Laboratories, the Security
* Research Division of Network Associates, Inc. under DARPA/SPAWAR
* contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
* research program
*
* Copyright (c) 1982, 1989, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* 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.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* @(#)dinode.h 8.9 (Berkeley) 3/29/95
*/
/*
* Copyright (c) 1982, 1986, 1989, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* 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.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* @(#)dir.h 8.5 (Berkeley) 4/27/95
*/
/*
* NOTE: COORDINATE ON-DISK FORMAT CHANGES WITH THE FREEBSD PROJECT.
*/
#ifndef _UFS_LFS_LFS_H_
#define _UFS_LFS_LFS_H_
@@ -66,6 +152,8 @@
#include <sys/mutex.h>
#include <sys/queue.h>
#include <sys/condvar.h>
#include <sys/mount.h>
#include <sys/pool.h>
/*
* Compile-time options for LFS.
@@ -83,9 +171,26 @@
#define LFS_UNUSED_INUM 0 /* 0: out of band inode number */
#define LFS_IFILE_INUM 1 /* 1: IFILE inode number */
/* 2: Root inode number */
#define LOSTFOUNDINO 3 /* 3: lost+found inode number */
#define LFS_LOSTFOUNDINO 3 /* 3: lost+found inode number */
#define LFS_FIRST_INUM 4 /* 4: first free inode number */
/*
* The root inode is the root of the file system. Inode 0 can't be used for
* normal purposes and historically bad blocks were linked to inode 1, thus
* the root inode is 2. (Inode 1 is no longer used for this purpose, however
* numerous dump tapes make this assumption, so we are stuck with it).
*/
#define ULFS_ROOTINO ((ino_t)2)
/*
* The Whiteout inode# is a dummy non-zero inode number which will
* never be allocated to a real file. It is used as a place holder
* in the directory entry which has been tagged as a LFS_DT_WHT entry.
* See the comments about ULFS_ROOTINO above.
*/
#define ULFS_WINO ((ino_t)1)
#define LFS_V1_SUMMARY_SIZE 512 /* V1 fixed summary size */
#define LFS_DFL_SUMMARY_SIZE 512 /* Default summary size */
@@ -93,84 +198,240 @@
#define LFS_MAXNAMLEN 255 /* maximum name length in a dir */
/* Adjustable filesystem parameters */
#define MIN_FREE_SEGS 20
#define MIN_RESV_SEGS 15
#define ULFS_NXADDR 2
#define ULFS_NDADDR 12 /* Direct addresses in inode. */
#define ULFS_NIADDR 3 /* Indirect addresses in inode. */
/*
* Adjustable filesystem parameters
*/
#ifndef LFS_ATIME_IFILE
# define LFS_ATIME_IFILE 0 /* Store atime info in ifile (optional in LFSv1) */
#endif
#define LFS_MARKV_MAXBLKCNT 65536 /* Max block count for lfs_markv() */
/* Misc. definitions */
#define BW_CLEAN 1 /* Flag for lfs_bwrite_ext() */
#define PG_DELWRI PG_PAGER1 /* Local def for delayed pageout */
/* Resource limits */
#define LFS_MAX_RESOURCE(x, u) (((x) >> 2) - 10 * (u))
#define LFS_WAIT_RESOURCE(x, u) (((x) >> 1) - ((x) >> 3) - 10 * (u))
#define LFS_INVERSE_MAX_RESOURCE(x, u) (((x) + 10 * (u)) << 2)
#define LFS_MAX_BUFS LFS_MAX_RESOURCE(nbuf, 1)
#define LFS_WAIT_BUFS LFS_WAIT_RESOURCE(nbuf, 1)
#define LFS_INVERSE_MAX_BUFS(n) LFS_INVERSE_MAX_RESOURCE(n, 1)
#define LFS_MAX_BYTES LFS_MAX_RESOURCE(bufmem_lowater, PAGE_SIZE)
#define LFS_INVERSE_MAX_BYTES(n) LFS_INVERSE_MAX_RESOURCE(n, PAGE_SIZE)
#define LFS_WAIT_BYTES LFS_WAIT_RESOURCE(bufmem_lowater, PAGE_SIZE)
#define LFS_MAX_DIROP ((desiredvnodes >> 2) + (desiredvnodes >> 3))
#define SIZEOF_DIROP(fs) (2 * ((fs)->lfs_bsize + DINODE1_SIZE))
#define LFS_MAX_FSDIROP(fs) \
((fs)->lfs_nclean <= (fs)->lfs_resvseg ? 0 : \
(((fs)->lfs_nclean - (fs)->lfs_resvseg) * (fs)->lfs_ssize) / \
(2 * SIZEOF_DIROP(fs)))
#define LFS_MAX_PAGES lfs_max_pages()
#define LFS_WAIT_PAGES lfs_wait_pages()
#define LFS_BUFWAIT 2 /* How long to wait if over *_WAIT_* */
#ifdef _KERNEL
int lfs_wait_pages(void);
int lfs_max_pages(void);
#endif /* _KERNEL */
/* How starved can we be before we start holding back page writes */
#define LFS_STARVED_FOR_SEGS(fs) ((fs)->lfs_nclean < (fs)->lfs_resvseg)
/*
* Reserved blocks for lfs_malloc
* Directories
*/
/* Structure to keep reserved blocks */
typedef struct lfs_res_blk {
void *p;
LIST_ENTRY(lfs_res_blk) res;
int size;
char inuse;
} res_t;
/*
* A directory consists of some number of blocks of LFS_DIRBLKSIZ
* bytes, where LFS_DIRBLKSIZ is chosen such that it can be transferred
* to disk in a single atomic operation (e.g. 512 bytes on most machines).
*
* Each LFS_DIRBLKSIZ byte block contains some number of directory entry
* structures, which are of variable length. Each directory entry has
* a struct lfs_direct at the front of it, containing its inode number,
* the length of the entry, and the length of the name contained in
* the entry. These are followed by the name padded to a 4 byte boundary.
* All names are guaranteed null terminated.
* The maximum length of a name in a directory is LFS_MAXNAMLEN.
*
* The macro DIRSIZ(fmt, dp) gives the amount of space required to represent
* a directory entry. Free space in a directory is represented by
* entries which have dp->d_reclen > DIRSIZ(fmt, dp). All LFS_DIRBLKSIZ bytes
* in a directory block are claimed by the directory entries. This
* usually results in the last entry in a directory having a large
* dp->d_reclen. When entries are deleted from a directory, the
* space is returned to the previous entry in the same directory
* block by increasing its dp->d_reclen. If the first entry of
* a directory block is free, then its dp->d_ino is set to 0.
* Entries other than the first in a directory do not normally have
* dp->d_ino set to 0.
*/
/* Types for lfs_newbuf and lfs_malloc */
#define LFS_NB_UNKNOWN -1
#define LFS_NB_SUMMARY 0
#define LFS_NB_SBLOCK 1
#define LFS_NB_IBLOCK 2
#define LFS_NB_CLUSTER 3
#define LFS_NB_CLEAN 4
#define LFS_NB_BLKIOV 5
#define LFS_NB_COUNT 6 /* always last */
/*
* Directory block size.
*/
#undef LFS_DIRBLKSIZ
#define LFS_DIRBLKSIZ DEV_BSIZE
/* Number of reserved memory blocks of each type */
#define LFS_N_SUMMARIES 2
#define LFS_N_SBLOCKS 1 /* Always 1, to throttle superblock writes */
#define LFS_N_IBLOCKS 16 /* In theory ssize/bsize; in practice around 2 */
#define LFS_N_CLUSTERS 16 /* In theory ssize/MAXPHYS */
#define LFS_N_CLEAN 0
#define LFS_N_BLKIOV 1
/*
* Convert between stat structure types and directory types.
*/
#define LFS_IFTODT(mode) (((mode) & 0170000) >> 12)
#define LFS_DTTOIF(dirtype) ((dirtype) << 12)
/* Total count of "large" (non-pool) types */
#define LFS_N_TOTAL (LFS_N_SUMMARIES + LFS_N_SBLOCKS + LFS_N_IBLOCKS + \
LFS_N_CLUSTERS + LFS_N_CLEAN + LFS_N_BLKIOV)
/*
* The LFS_DIRSIZ macro gives the minimum record length which will hold
* the directory entry. This requires the amount of space in struct lfs_direct
* without the d_name field, plus enough space for the name with a terminating
* null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
*/
#define LFS_DIRECTSIZ(namlen) \
((sizeof(struct lfs_direct) - (LFS_MAXNAMLEN+1)) + (((namlen)+1 + 3) &~ 3))
/* Counts for pool types */
#define LFS_N_CL LFS_N_CLUSTERS
#define LFS_N_BPP 2
#define LFS_N_SEG 2
#if (BYTE_ORDER == LITTLE_ENDIAN)
#define LFS_DIRSIZ(oldfmt, dp, needswap) \
(((oldfmt) && !(needswap)) ? \
LFS_DIRECTSIZ((dp)->d_type) : LFS_DIRECTSIZ((dp)->d_namlen))
#else
#define LFS_DIRSIZ(oldfmt, dp, needswap) \
(((oldfmt) && (needswap)) ? \
LFS_DIRECTSIZ((dp)->d_type) : LFS_DIRECTSIZ((dp)->d_namlen))
#endif
/* Constants for the first argument of LFS_DIRSIZ */
#define LFS_OLDDIRFMT 1
#define LFS_NEWDIRFMT 0
/*
* Theoretically, directories can be more than 2Gb in length; however, in
* practice this seems unlikely. So, we define the type doff_t as a 32-bit
* quantity to keep down the cost of doing lookup on a 32-bit machine.
*/
#define doff_t int32_t
#define lfs_doff_t int32_t
#define LFS_MAXDIRSIZE (0x7fffffff)
/*
* File types for d_type
*/
#define LFS_DT_UNKNOWN 0
#define LFS_DT_FIFO 1
#define LFS_DT_CHR 2
#define LFS_DT_DIR 4
#define LFS_DT_BLK 6
#define LFS_DT_REG 8
#define LFS_DT_LNK 10
#define LFS_DT_SOCK 12
#define LFS_DT_WHT 14
/*
* (See notes above)
*/
#define d_ino d_fileno
struct lfs_direct {
u_int32_t d_fileno; /* inode number of entry */
u_int16_t d_reclen; /* length of this record */
u_int8_t d_type; /* file type, see below */
u_int8_t d_namlen; /* length of string in d_name */
char d_name[LFS_MAXNAMLEN + 1];/* name with length <= LFS_MAXNAMLEN */
};
/*
* Template for manipulating directories. Should use struct lfs_direct's,
* but the name field is LFS_MAXNAMLEN - 1, and this just won't do.
*/
struct lfs_dirtemplate {
u_int32_t dot_ino;
int16_t dot_reclen;
u_int8_t dot_type;
u_int8_t dot_namlen;
char dot_name[4]; /* must be multiple of 4 */
u_int32_t dotdot_ino;
int16_t dotdot_reclen;
u_int8_t dotdot_type;
u_int8_t dotdot_namlen;
char dotdot_name[4]; /* ditto */
};
/*
* This is the old format of directories, sans type element.
*/
struct lfs_odirtemplate {
u_int32_t dot_ino;
int16_t dot_reclen;
u_int16_t dot_namlen;
char dot_name[4]; /* must be multiple of 4 */
u_int32_t dotdot_ino;
int16_t dotdot_reclen;
u_int16_t dotdot_namlen;
char dotdot_name[4]; /* ditto */
};
/*
* Inodes
*/
/*
* A dinode contains all the meta-data associated with a LFS file.
* This structure defines the on-disk format of a dinode. Since
* this structure describes an on-disk structure, all its fields
* are defined by types with precise widths.
*/
struct ulfs1_dinode {
u_int16_t di_mode; /* 0: IFMT, permissions; see below. */
int16_t di_nlink; /* 2: File link count. */
u_int32_t di_inumber; /* 4: Inode number. */
u_int64_t di_size; /* 8: File byte count. */
int32_t di_atime; /* 16: Last access time. */
int32_t di_atimensec; /* 20: Last access time. */
int32_t di_mtime; /* 24: Last modified time. */
int32_t di_mtimensec; /* 28: Last modified time. */
int32_t di_ctime; /* 32: Last inode change time. */
int32_t di_ctimensec; /* 36: Last inode change time. */
int32_t di_db[ULFS_NDADDR]; /* 40: Direct disk blocks. */
int32_t di_ib[ULFS_NIADDR]; /* 88: Indirect disk blocks. */
u_int32_t di_flags; /* 100: Status flags (chflags). */
u_int32_t di_blocks; /* 104: Blocks actually held. */
int32_t di_gen; /* 108: Generation number. */
u_int32_t di_uid; /* 112: File owner. */
u_int32_t di_gid; /* 116: File group. */
u_int64_t di_modrev; /* 120: i_modrev for NFSv4 */
};
struct ulfs2_dinode {
u_int16_t di_mode; /* 0: IFMT, permissions; see below. */
int16_t di_nlink; /* 2: File link count. */
u_int32_t di_uid; /* 4: File owner. */
u_int32_t di_gid; /* 8: File group. */
u_int32_t di_blksize; /* 12: Inode blocksize. */
u_int64_t di_size; /* 16: File byte count. */
u_int64_t di_blocks; /* 24: Bytes actually held. */
int64_t di_atime; /* 32: Last access time. */
int64_t di_mtime; /* 40: Last modified time. */
int64_t di_ctime; /* 48: Last inode change time. */
int64_t di_birthtime; /* 56: Inode creation time. */
int32_t di_mtimensec; /* 64: Last modified time. */
int32_t di_atimensec; /* 68: Last access time. */
int32_t di_ctimensec; /* 72: Last inode change time. */
int32_t di_birthnsec; /* 76: Inode creation time. */
int32_t di_gen; /* 80: Generation number. */
u_int32_t di_kernflags; /* 84: Kernel flags. */
u_int32_t di_flags; /* 88: Status flags (chflags). */
int32_t di_extsize; /* 92: External attributes block. */
int64_t di_extb[ULFS_NXADDR];/* 96: External attributes block. */
int64_t di_db[ULFS_NDADDR]; /* 112: Direct disk blocks. */
int64_t di_ib[ULFS_NIADDR]; /* 208: Indirect disk blocks. */
u_int64_t di_modrev; /* 232: i_modrev for NFSv4 */
int64_t di_spare[2]; /* 240: Reserved; currently unused */
};
/*
* The di_db fields may be overlaid with other information for
* file types that do not have associated disk storage. Block
* and character devices overlay the first data block with their
* dev_t value. Short symbolic links place their path in the
* di_db area.
*/
#define di_rdev di_db[0]
/* Size of the on-disk inode. */
#define LFS_DINODE1_SIZE (sizeof(struct ulfs1_dinode)) /* 128 */
#define LFS_DINODE2_SIZE (sizeof(struct ulfs2_dinode))
/* File types, found in the upper bits of di_mode. */
#define LFS_IFMT 0170000 /* Mask of file type. */
#define LFS_IFIFO 0010000 /* Named pipe (fifo). */
#define LFS_IFCHR 0020000 /* Character device. */
#define LFS_IFDIR 0040000 /* Directory file. */
#define LFS_IFBLK 0060000 /* Block device. */
#define LFS_IFREG 0100000 /* Regular file. */
#define LFS_IFLNK 0120000 /* Symbolic link. */
#define LFS_IFSOCK 0140000 /* UNIX domain socket. */
#define LFS_IFWHT 0160000 /* Whiteout. */
/*
* Maximum length of a symlink that can be stored within the inode.
*/
#define ULFS1_MAXSYMLINKLEN ((ULFS_NDADDR + ULFS_NIADDR) * sizeof(int32_t))
#define ULFS2_MAXSYMLINKLEN ((ULFS_NDADDR + ULFS_NIADDR) * sizeof(int64_t))
#define ULFS_MAXSYMLINKLEN(ip) \
((ip)->i_ump->um_fstype == ULFS1) ? \
ULFS1_MAXSYMLINKLEN : ULFS2_MAXSYMLINKLEN
/*
* "struct buf" associated definitions
@@ -183,9 +444,6 @@ typedef struct lfs_res_blk {
/* Unused logical block number */
#define LFS_UNUSED_LBN -1
/* Determine if a buffer belongs to the ifile */
#define IS_IFILE(bp) (VTOI(bp->b_vp)->i_number == LFS_IFILE_INUM)
# define LFS_LOCK_BUF(bp) do { \
if (((bp)->b_flags & B_LOCKED) == 0 && bp->b_iodone == NULL) { \
mutex_enter(&lfs_lock); \
@@ -209,104 +467,10 @@ typedef struct lfs_res_blk {
(bp)->b_flags &= ~B_LOCKED; \
} while (0)
#ifdef _KERNEL
extern u_long bufmem_lowater, bufmem_hiwater; /* XXX */
# define LFS_IS_MALLOC_BUF(bp) ((bp)->b_iodone == lfs_callback)
# ifdef DEBUG
# define LFS_DEBUG_COUNTLOCKED(m) do { \
if (lfs_debug_log_subsys[DLOG_LLIST]) { \
lfs_countlocked(&locked_queue_count, &locked_queue_bytes, (m)); \
cv_broadcast(&locked_queue_cv); \
} \
} while (0)
# else
# define LFS_DEBUG_COUNTLOCKED(m)
# endif
/* log for debugging writes to the Ifile */
# ifdef DEBUG
struct lfs_log_entry {
const char *op;
const char *file;
int pid;
int line;
daddr_t block;
unsigned long flags;
};
extern int lfs_lognum;
extern struct lfs_log_entry lfs_log[LFS_LOGLENGTH];
# define LFS_BWRITE_LOG(bp) lfs_bwrite_log((bp), __FILE__, __LINE__)
# define LFS_ENTER_LOG(theop, thefile, theline, lbn, theflags, thepid) do {\
int _s; \
\
mutex_enter(&lfs_lock); \
_s = splbio(); \
lfs_log[lfs_lognum].op = theop; \
lfs_log[lfs_lognum].file = thefile; \
lfs_log[lfs_lognum].line = (theline); \
lfs_log[lfs_lognum].pid = (thepid); \
lfs_log[lfs_lognum].block = (lbn); \
lfs_log[lfs_lognum].flags = (theflags); \
lfs_lognum = (lfs_lognum + 1) % LFS_LOGLENGTH; \
splx(_s); \
mutex_exit(&lfs_lock); \
} while (0)
# define LFS_BCLEAN_LOG(fs, bp) do { \
if ((bp)->b_vp == (fs)->lfs_ivnode) \
LFS_ENTER_LOG("clear", __FILE__, __LINE__, \
bp->b_lblkno, bp->b_flags, curproc->p_pid);\
} while (0)
/* Must match list in lfs_vfsops.c ! */
# define DLOG_RF 0 /* roll forward */
# define DLOG_ALLOC 1 /* inode alloc */
# define DLOG_AVAIL 2 /* lfs_{,r,f}avail */
# define DLOG_FLUSH 3 /* flush */
# define DLOG_LLIST 4 /* locked list accounting */
# define DLOG_WVNODE 5 /* vflush/writevnodes verbose */
# define DLOG_VNODE 6 /* vflush/writevnodes */
# define DLOG_SEG 7 /* segwrite */
# define DLOG_SU 8 /* seguse accounting */
# define DLOG_CLEAN 9 /* cleaner routines */
# define DLOG_MOUNT 10 /* mount/unmount */
# define DLOG_PAGE 11 /* putpages/gop_write */
# define DLOG_DIROP 12 /* dirop accounting */
# define DLOG_MALLOC 13 /* lfs_malloc accounting */
# define DLOG_MAX 14 /* The terminator */
# define DLOG(a) lfs_debug_log a
# else /* ! DEBUG */
# define LFS_BCLEAN_LOG(fs, bp)
# define LFS_BWRITE_LOG(bp) VOP_BWRITE((bp)->b_vp, (bp))
# define DLOG(a)
# endif /* ! DEBUG */
#else /* ! _KERNEL */
# define LFS_BWRITE_LOG(bp) VOP_BWRITE((bp))
#endif /* _KERNEL */
#ifdef _KERNEL
/* Filehandle structure for exported LFSes */
struct lfid {
struct ufid lfid_ufid;
#define lfid_len lfid_ufid.ufid_len
#define lfid_ino lfid_ufid.ufid_ino
#define lfid_gen lfid_ufid.ufid_gen
uint32_t lfid_ident;
};
#endif /* _KERNEL */
/*
* "struct inode" associated definitions
*/
/* Address calculations for metadata located in the inode */
#define S_INDIR(fs) -NDADDR
#define D_INDIR(fs) (S_INDIR(fs) - NINDIR(fs) - 1)
#define T_INDIR(fs) (D_INDIR(fs) - NINDIR(fs) * NINDIR(fs) - 1)
/* For convenience */
#define IN_ALLMOD (IN_MODIFIED|IN_ACCESS|IN_CHANGE|IN_UPDATE|IN_MODIFY|IN_ACCESSED|IN_CLEANING)
@@ -337,20 +501,6 @@ struct lfid {
while ((ip)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY)) \
lfs_itimes(ip, acc, mod, cre)
/*
* "struct vnode" associated definitions
*/
/* Heuristic emptiness measure */
#define VPISEMPTY(vp) (LIST_EMPTY(&(vp)->v_dirtyblkhd) && \
!(vp->v_type == VREG && (vp)->v_iflag & VI_ONWORKLST) &&\
VTOI(vp)->i_lfs_nbtree == 0)
#define WRITEINPROG(vp) ((vp)->v_numoutput > 0 || \
(!LIST_EMPTY(&(vp)->v_dirtyblkhd) && \
!(VTOI(vp)->i_flag & (IN_MODIFIED | IN_ACCESSED | IN_CLEANING))))
/*
* On-disk and in-memory checkpoint segment usage structure.
*/
@@ -592,6 +742,7 @@ struct segsum_v1 {
#define SS_CONT 0x02 /* more partials to finish this write*/
#define SS_CLEAN 0x04 /* written by the cleaner */
#define SS_RFW 0x08 /* written by the roll-forward agent */
#define SS_RECLAIM 0x10 /* written by the roll-forward agent */
u_int16_t ss_flags; /* 24: used for directory operations */
u_int16_t ss_pad; /* 26: extra space */
/* FINFO's and inode daddr's... */
@@ -608,7 +759,8 @@ struct segsum {
u_int16_t ss_nfinfo; /* 20: number of file info structures */
u_int16_t ss_ninos; /* 22: number of inodes in summary */
u_int16_t ss_flags; /* 24: used for directory operations */
u_int8_t ss_pad[6]; /* 26: extra space */
u_int8_t ss_pad[2]; /* 26: extra space */
u_int32_t ss_reclino; /* 28: inode being reclaimed */
u_int64_t ss_serial; /* 32: serial number */
u_int64_t ss_create; /* 40: time stamp */
/* FINFO's and inode daddr's... */
@@ -697,7 +849,7 @@ struct dlfs {
u_int32_t dlfs_inodefmt; /* 360: inode format version */
u_int32_t dlfs_interleave; /* 364: segment interleave */
u_int32_t dlfs_ident; /* 368: per-fs identifier */
u_int32_t dlfs_fsbtodb; /* 372: fsbtodb abd dbtodsb shift constant */
u_int32_t dlfs_fsbtodb; /* 372: fsbtodb and dbtodsb shift constant */
u_int32_t dlfs_resvseg; /* 376: segments reserved for the cleaner */
int8_t dlfs_pad[128]; /* 380: round to 512 bytes */
/* Checksum -- last valid disk field. */
@@ -819,7 +971,7 @@ struct lfs {
int lfs_nadirop; /* number of active dirop nodes */
long lfs_ravail; /* blocks pre-reserved for writing */
long lfs_favail; /* blocks pre-reserved for writing */
res_t *lfs_resblk; /* Reserved memory for pageout */
struct lfs_res_blk *lfs_resblk; /* Reserved memory for pageout */
TAILQ_HEAD(, inode) lfs_dchainhd; /* dirop vnodes */
TAILQ_HEAD(, inode) lfs_pchainhd; /* paging vnodes */
#define LFS_RESHASH_WIDTH 17
@@ -840,68 +992,88 @@ struct lfs {
int lfs_nowrap; /* Suspend log wrap */
int lfs_wrappass; /* Allow first log wrap requester to pass */
int lfs_wrapstatus; /* Wrap status */
int lfs_reclino; /* Inode being reclaimed */
int lfs_startseg; /* Segment we started writing at */
LIST_HEAD(, segdelta) lfs_segdhd; /* List of pending trunc accounting events */
#ifdef _KERNEL
/* ULFS-level information */
u_int32_t um_flags; /* ULFS flags (below) */
u_long um_nindir; /* indirect ptrs per block */
u_long um_lognindir; /* log2 of um_nindir */
u_long um_bptrtodb; /* indir ptr to disk block */
u_long um_seqinc; /* inc between seq blocks */
int um_maxsymlinklen;
int um_dirblksiz;
u_int64_t um_maxfilesize;
/* Stuff used by quota2 code, not currently operable */
unsigned lfs_use_quota2 : 1;
uint32_t lfs_quota_magic;
uint8_t lfs_quota_flags;
uint64_t lfs_quotaino[2];
#endif
};
/* NINDIR is the number of indirects in a file system block. */
#define NINDIR(fs) ((fs)->lfs_nindir)
/* LFS_NINDIR is the number of indirects in a file system block. */
#define LFS_NINDIR(fs) ((fs)->lfs_nindir)
/* INOPB is the number of inodes in a secondary storage block. */
#define INOPB(fs) ((fs)->lfs_inopb)
/* INOPF is the number of inodes in a fragment. */
#define INOPF(fs) ((fs)->lfs_inopf)
/* LFS_INOPB is the number of inodes in a secondary storage block. */
#define LFS_INOPB(fs) ((fs)->lfs_inopb)
/* LFS_INOPF is the number of inodes in a fragment. */
#define LFS_INOPF(fs) ((fs)->lfs_inopf)
#define blksize(fs, ip, lbn) \
(((lbn) >= NDADDR || (ip)->i_ffs1_size >= ((lbn) + 1) << (fs)->lfs_bshift) \
#define lfs_blksize(fs, ip, lbn) \
(((lbn) >= ULFS_NDADDR || (ip)->i_ffs1_size >= ((lbn) + 1) << (fs)->lfs_bshift) \
? (fs)->lfs_bsize \
: (fragroundup(fs, blkoff(fs, (ip)->i_ffs1_size))))
#define blkoff(fs, loc) ((int)((loc) & (fs)->lfs_bmask))
#define fragoff(fs, loc) /* calculates (loc % fs->lfs_fsize) */ \
: (lfs_fragroundup(fs, lfs_blkoff(fs, (ip)->i_ffs1_size))))
#define lfs_blkoff(fs, loc) ((int)((loc) & (fs)->lfs_bmask))
#define lfs_fragoff(fs, loc) /* calculates (loc % fs->lfs_fsize) */ \
((int)((loc) & (fs)->lfs_ffmask))
#if defined (_KERNEL)
#define fsbtodb(fs, b) ((b) << ((fs)->lfs_ffshift - DEV_BSHIFT))
#define dbtofsb(fs, b) ((b) >> ((fs)->lfs_ffshift - DEV_BSHIFT))
#if defined(_KERNEL)
#define LFS_FSBTODB(fs, b) ((b) << ((fs)->lfs_ffshift - DEV_BSHIFT))
#define LFS_DBTOFSB(fs, b) ((b) >> ((fs)->lfs_ffshift - DEV_BSHIFT))
#else
#define fsbtodb(fs, b) ((b) << (fs)->lfs_fsbtodb)
#define dbtofsb(fs, b) ((b) >> (fs)->lfs_fsbtodb)
#define LFS_FSBTODB(fs, b) ((b) << (fs)->lfs_fsbtodb)
#define LFS_DBTOFSB(fs, b) ((b) >> (fs)->lfs_fsbtodb)
#endif
#define lblkno(fs, loc) ((loc) >> (fs)->lfs_bshift)
#define lblktosize(fs, blk) ((blk) << (fs)->lfs_bshift)
#define lfs_lblkno(fs, loc) ((loc) >> (fs)->lfs_bshift)
#define lfs_lblktosize(fs, blk) ((blk) << (fs)->lfs_bshift)
#define fsbtob(fs, b) ((b) << (fs)->lfs_ffshift)
#define btofsb(fs, b) ((b) >> (fs)->lfs_ffshift)
#define lfs_fsbtob(fs, b) ((b) << (fs)->lfs_ffshift)
#define lfs_btofsb(fs, b) ((b) >> (fs)->lfs_ffshift)
#define numfrags(fs, loc) /* calculates (loc / fs->lfs_fsize) */ \
#define lfs_numfrags(fs, loc) /* calculates (loc / fs->lfs_fsize) */ \
((loc) >> (fs)->lfs_ffshift)
#define blkroundup(fs, size) /* calculates roundup(size, fs->lfs_bsize) */ \
#define lfs_blkroundup(fs, size)/* calculates roundup(size, fs->lfs_bsize) */ \
((off_t)(((size) + (fs)->lfs_bmask) & (~(fs)->lfs_bmask)))
#define fragroundup(fs, size) /* calculates roundup(size, fs->lfs_fsize) */ \
#define lfs_fragroundup(fs, size)/* calculates roundup(size, fs->lfs_fsize) */ \
((off_t)(((size) + (fs)->lfs_ffmask) & (~(fs)->lfs_ffmask)))
#define fragstoblks(fs, frags)/* calculates (frags / fs->fs_frag) */ \
#define lfs_fragstoblks(fs, frags)/* calculates (frags / fs->fs_frag) */ \
((frags) >> (fs)->lfs_fbshift)
#define blkstofrags(fs, blks) /* calculates (blks * fs->fs_frag) */ \
#define lfs_blkstofrags(fs, blks)/* calculates (blks * fs->fs_frag) */ \
((blks) << (fs)->lfs_fbshift)
#define fragnum(fs, fsb) /* calculates (fsb % fs->lfs_frag) */ \
#define lfs_fragnum(fs, fsb) /* calculates (fsb % fs->lfs_frag) */ \
((fsb) & ((fs)->lfs_frag - 1))
#define blknum(fs, fsb) /* calculates rounddown(fsb, fs->lfs_frag) */ \
#define lfs_blknum(fs, fsb) /* calculates rounddown(fsb, fs->lfs_frag) */ \
((fsb) &~ ((fs)->lfs_frag - 1))
#define dblksize(fs, dp, lbn) \
(((lbn) >= NDADDR || (dp)->di_size >= ((lbn) + 1) << (fs)->lfs_bshift)\
#define lfs_dblksize(fs, dp, lbn) \
(((lbn) >= ULFS_NDADDR || (dp)->di_size >= ((lbn) + 1) << (fs)->lfs_bshift)\
? (fs)->lfs_bsize \
: (fragroundup(fs, blkoff(fs, (dp)->di_size))))
: (lfs_fragroundup(fs, lfs_blkoff(fs, (dp)->di_size))))
#define segsize(fs) ((fs)->lfs_version == 1 ? \
lblktosize((fs), (fs)->lfs_ssize) : \
#define lfs_segsize(fs) ((fs)->lfs_version == 1 ? \
lfs_lblktosize((fs), (fs)->lfs_ssize) : \
(fs)->lfs_ssize)
#define segtod(fs, seg) (((fs)->lfs_version == 1 ? \
#define lfs_segtod(fs, seg) (((fs)->lfs_version == 1 ? \
(fs)->lfs_ssize << (fs)->lfs_blktodb : \
btofsb((fs), (fs)->lfs_ssize)) * (seg))
#define dtosn(fs, daddr) /* block address to segment number */ \
((uint32_t)(((daddr) - (fs)->lfs_start) / segtod((fs), 1)))
#define sntod(fs, sn) /* segment number to disk address */ \
((daddr_t)(segtod((fs), (sn)) + (fs)->lfs_start))
lfs_btofsb((fs), (fs)->lfs_ssize)) * (seg))
#define lfs_dtosn(fs, daddr) /* block address to segment number */ \
((uint32_t)(((daddr) - (fs)->lfs_start) / lfs_segtod((fs), 1)))
#define lfs_sntod(fs, sn) /* segment number to disk address */ \
((daddr_t)(lfs_segtod((fs), (sn)) + (fs)->lfs_start))
/*
* Structures used by lfs_bmapv and lfs_markv to communicate information
@@ -935,7 +1107,7 @@ struct segment {
struct buf **cbpp; /* pointer to next available bp */
struct buf **start_bpp; /* pointer to first bp in this set */
struct buf *ibp; /* buffer pointer to inode page */
struct ufs1_dinode *idp; /* pointer to ifile dinode */
struct ulfs1_dinode *idp; /* pointer to ifile dinode */
struct finfo *fip; /* current fileinfo pointer */
struct vnode *vp; /* vnode being gathered */
void *segsum; /* segment summary info */
@@ -945,82 +1117,44 @@ struct segment {
u_int32_t seg_number; /* number of this segment */
int32_t *start_lbp; /* beginning lbn for this set */
#define SEGM_CKP 0x01 /* doing a checkpoint */
#define SEGM_CLEAN 0x02 /* cleaner call; don't sort */
#define SEGM_SYNC 0x04 /* wait for segment */
#define SEGM_PROT 0x08 /* don't inactivate at segunlock */
#define SEGM_PAGEDAEMON 0x10 /* pagedaemon called us */
#define SEGM_WRITERD 0x20 /* LFS writed called us */
#define SEGM_FORCE_CKP 0x40 /* Force checkpoint right away */
#define SEGM_CKP 0x0001 /* doing a checkpoint */
#define SEGM_CLEAN 0x0002 /* cleaner call; don't sort */
#define SEGM_SYNC 0x0004 /* wait for segment */
#define SEGM_PROT 0x0008 /* don't inactivate at segunlock */
#define SEGM_PAGEDAEMON 0x0010 /* pagedaemon called us */
#define SEGM_WRITERD 0x0020 /* LFS writed called us */
#define SEGM_FORCE_CKP 0x0040 /* Force checkpoint right away */
#define SEGM_RECLAIM 0x0080 /* Writing to reclaim vnode */
#define SEGM_SINGLE 0x0100 /* Opportunistic writevnodes */
u_int16_t seg_flags; /* run-time flags for this segment */
u_int32_t seg_iocount; /* number of ios pending */
int ndupino; /* number of duplicate inodes */
};
#ifdef _KERNEL
struct lfs_cluster {
size_t bufsize; /* Size of kept data */
struct buf **bpp; /* Array of kept buffers */
int bufcount; /* Number of kept buffers */
#define LFS_CL_MALLOC 0x00000001
#define LFS_CL_SHIFT 0x00000002
#define LFS_CL_SYNC 0x00000004
u_int32_t flags; /* Flags */
struct lfs *fs; /* LFS that this belongs to */
struct segment *seg; /* Segment structure, for LFS_CL_SYNC */
};
/*
* Splay tree containing block numbers allocated through lfs_balloc.
*/
struct lbnentry {
SPLAY_ENTRY(lbnentry) entry;
daddr_t lbn;
};
#endif /* _KERNEL */
/*
* LFS inode extensions.
*/
struct lfs_inode_ext {
off_t lfs_osize; /* size of file on disk */
u_int32_t lfs_effnblocks; /* number of blocks when i/o completes */
size_t lfs_fragsize[NDADDR]; /* size of on-disk direct blocks */
TAILQ_ENTRY(inode) lfs_dchain; /* Dirop chain. */
TAILQ_ENTRY(inode) lfs_pchain; /* Paging chain. */
#define LFSI_NO_GOP_WRITE 0x01
#define LFSI_DELETED 0x02
#define LFSI_WRAPBLOCK 0x04
#define LFSI_WRAPWAIT 0x08
u_int32_t lfs_iflags; /* Inode flags */
daddr_t lfs_hiblk; /* Highest lbn held by inode */
#ifdef _KERNEL
SPLAY_HEAD(lfs_splay, lbnentry) lfs_lbtree; /* Tree of balloc'd lbns */
int lfs_nbtree; /* Size of tree */
LIST_HEAD(, segdelta) lfs_segdhd;
#endif
int16_t lfs_odnlink; /* on-disk nlink count for cleaner */
};
#define i_lfs_osize inode_ext.lfs->lfs_osize
#define i_lfs_effnblks inode_ext.lfs->lfs_effnblocks
#define i_lfs_fragsize inode_ext.lfs->lfs_fragsize
#define i_lfs_dchain inode_ext.lfs->lfs_dchain
#define i_lfs_pchain inode_ext.lfs->lfs_pchain
#define i_lfs_iflags inode_ext.lfs->lfs_iflags
#define i_lfs_hiblk inode_ext.lfs->lfs_hiblk
#define i_lfs_lbtree inode_ext.lfs->lfs_lbtree
#define i_lfs_nbtree inode_ext.lfs->lfs_nbtree
#define i_lfs_segdhd inode_ext.lfs->lfs_segdhd
#define i_lfs_odnlink inode_ext.lfs->lfs_odnlink
/*
* Macros for determining free space on the disk, with the variable metadata
* of segment summaries and inode blocks taken into account.
*/
/* Estimate number of clean blocks not available for writing */
#define LFS_EST_CMETA(F) (int32_t)((((F)->lfs_dmeta * \
(int64_t)(F)->lfs_nclean) / \
((F)->lfs_nseg - (F)->lfs_nclean)))
/*
* Estimate number of clean blocks not available for writing because
* they will contain metadata or overhead. This is calculated as
*
* E = ((C * M / D) * D + (0) * (T - D)) / T
* or more simply
* E = (C * M) / T
*
* where
* C is the clean space,
* D is the dirty space,
* M is the dirty metadata, and
* T = C + D is the total space on disk.
*
* This approximates the old formula of E = C * M / D when D is close to T,
* but avoids falsely reporting "disk full" when the sample size (D) is small.
*/
#define LFS_EST_CMETA(F) (int32_t)(( \
((F)->lfs_dmeta * (int64_t)(F)->lfs_nclean) / \
((F)->lfs_nseg)))
/* Estimate total size of the disk not including metadata */
#define LFS_EST_NONMETA(F) ((F)->lfs_dsize - (F)->lfs_dmeta - LFS_EST_CMETA(F))
@@ -1046,10 +1180,10 @@ struct lfs_inode_ext {
/*
* The minimum number of blocks to create a new inode. This is:
* directory direct block (1) + NIADDR indirect blocks + inode block (1) +
* ifile direct block (1) + NIADDR indirect blocks = 3 + 2 * NIADDR blocks.
* directory direct block (1) + ULFS_NIADDR indirect blocks + inode block (1) +
* ifile direct block (1) + ULFS_NIADDR indirect blocks = 3 + 2 * ULFS_NIADDR blocks.
*/
#define LFS_NRESERVE(F) (btofsb((F), (2 * NIADDR + 3) << (F)->lfs_bshift))
#define LFS_NRESERVE(F) (lfs_btofsb((F), (2 * ULFS_NIADDR + 3) << (F)->lfs_bshift))
/* Statistics Counters */
struct lfs_stats { /* Must match sysctl list in lfs_vfsops.h ! */
@@ -1070,9 +1204,6 @@ struct lfs_stats { /* Must match sysctl list in lfs_vfsops.h ! */
u_int clean_vnlocked;
u_int segs_reclaimed;
};
#ifdef _KERNEL
extern struct lfs_stats lfs_stats;
#endif
/* Fcntls to take the place of the lfs syscalls */
struct lfs_fcntl_markv {
@@ -1100,31 +1231,6 @@ struct lfs_fhandle {
# define LFS_WRAP_WAITING 0x1
#define LFCNWRAPSTATUS _FCNW_FSPRIV('L', 13, int)
/*
* Compat. Defined for kernel only. Userland always uses
* "the one true version".
*/
#ifdef _KERNEL
#include <compat/sys/time_types.h>
#define LFCNSEGWAITALL_COMPAT _FCNW_FSPRIV('L', 0, struct timeval50)
#define LFCNSEGWAIT_COMPAT _FCNW_FSPRIV('L', 1, struct timeval50)
#define LFCNIFILEFH_COMPAT _FCNW_FSPRIV('L', 5, struct lfs_fhandle)
#define LFCNIFILEFH_COMPAT2 _FCN_FSPRIV(F_FSOUT, 'L', 11, 32)
#define LFCNWRAPSTOP_COMPAT _FCNO_FSPRIV('L', 9)
#define LFCNWRAPGO_COMPAT _FCNO_FSPRIV('L', 10)
#define LFCNSEGWAITALL_COMPAT_50 _FCNR_FSPRIV('L', 0, struct timeval50)
#define LFCNSEGWAIT_COMPAT_50 _FCNR_FSPRIV('L', 1, struct timeval50)
#endif
#ifdef _KERNEL
/* XXX MP */
#define LFS_SEGLOCK_HELD(fs) \
((fs)->lfs_seglock != 0 && \
(fs)->lfs_lockpid == curproc->p_pid && \
(fs)->lfs_locklwp == curlwp->l_lid)
#endif /* _KERNEL */
/* Debug segment lock */
#ifdef notyet
# define ASSERT_SEGLOCK(fs) KASSERT(LFS_SEGLOCK_HELD(fs))
@@ -1148,6 +1254,13 @@ struct lfs_fhandle {
# define ASSERT_MAYBE_SEGLOCK(x)
#endif /* !notyet */
/*
* Arguments to mount LFS filesystems
*/
struct ulfs_args {
char *fspec; /* block special device to mount */
};
__BEGIN_DECLS
void lfs_itimes(struct inode *, const struct timespec *,
const struct timespec *, const struct timespec *);
+27 -31
View File
@@ -1,4 +1,4 @@
/* $NetBSD: lfs_alloc.c,v 1.111 2011/06/12 03:36:01 rmind Exp $ */
/* $NetBSD: lfs_alloc.c,v 1.119 2013/07/28 01:25:05 dholland Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003, 2007 The NetBSD Foundation, Inc.
@@ -60,7 +60,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_alloc.c,v 1.111 2011/06/12 03:36:01 rmind Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_alloc.c,v 1.119 2013/07/28 01:25:05 dholland Exp $");
#if defined(_KERNEL_OPT)
#include "opt_quota.h"
@@ -80,13 +80,14 @@ __KERNEL_RCSID(0, "$NetBSD: lfs_alloc.c,v 1.111 2011/06/12 03:36:01 rmind Exp $"
#include <sys/tree.h>
#include <sys/kauth.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/ufs_extern.h>
#include <ufs/lfs/ulfs_quotacommon.h>
#include <ufs/lfs/ulfs_inode.h>
#include <ufs/lfs/ulfsmount.h>
#include <ufs/lfs/ulfs_extern.h>
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_extern.h>
#include <ufs/lfs/lfs_kernel.h>
/* Constants for inode free bitmap */
#define BMSHIFT 5 /* 2 ** 5 = 32 */
@@ -126,7 +127,7 @@ lfs_extend_ifile(struct lfs *fs, kauth_cred_t cred)
vp = fs->lfs_ivnode;
ip = VTOI(vp);
blkno = lblkno(fs, ip->i_size);
blkno = lfs_lblkno(fs, ip->i_size);
if ((error = lfs_balloc(vp, ip->i_size, fs->lfs_bsize, cred, 0,
&bp)) != 0) {
return (error);
@@ -207,7 +208,6 @@ lfs_valloc(struct vnode *pvp, int mode, kauth_cred_t cred,
ASSERT_NO_SEGLOCK(fs);
lfs_seglock(fs, SEGM_PROT);
vn_lock(fs->lfs_ivnode, LK_EXCLUSIVE);
/* Get the head of the freelist. */
LFS_GET_HEADFREE(fs, cip, cbp, &new_ino);
@@ -236,7 +236,6 @@ lfs_valloc(struct vnode *pvp, int mode, kauth_cred_t cred,
if (fs->lfs_freehd == LFS_UNUSED_INUM) {
if ((error = lfs_extend_ifile(fs, cred)) != 0) {
LFS_PUT_HEADFREE(fs, cip, cbp, new_ino);
VOP_UNLOCK(fs->lfs_ivnode);
lfs_segunlock(fs);
return error;
}
@@ -252,7 +251,6 @@ lfs_valloc(struct vnode *pvp, int mode, kauth_cred_t cred,
mutex_exit(&lfs_lock);
++fs->lfs_nfiles;
VOP_UNLOCK(fs->lfs_ivnode);
lfs_segunlock(fs);
return lfs_ialloc(fs, pvp, new_ino, new_gen, vpp);
@@ -271,7 +269,7 @@ lfs_ialloc(struct lfs *fs, struct vnode *pvp, ino_t new_ino, int new_gen,
ASSERT_NO_SEGLOCK(fs);
vp = *vpp;
mutex_enter(&ufs_hashlock);
mutex_enter(&ulfs_hashlock);
/* Create an inode to associate with the vnode. */
lfs_vcreate(pvp->v_mount, new_ino, vp);
@@ -292,14 +290,14 @@ lfs_ialloc(struct lfs *fs, struct vnode *pvp, ino_t new_ino, int new_gen,
}
/* Insert into the inode hash table. */
ufs_ihashins(ip);
mutex_exit(&ufs_hashlock);
ulfs_ihashins(ip);
mutex_exit(&ulfs_hashlock);
ufs_vinit(vp->v_mount, lfs_specop_p, lfs_fifoop_p, vpp);
ulfs_vinit(vp->v_mount, lfs_specop_p, lfs_fifoop_p, vpp);
vp = *vpp;
ip = VTOI(vp);
memset(ip->i_lfs_fragsize, 0, NDADDR * sizeof(*ip->i_lfs_fragsize));
memset(ip->i_lfs_fragsize, 0, ULFS_NDADDR * sizeof(*ip->i_lfs_fragsize));
uvm_vnp_setsize(vp, 0);
lfs_mark_vnode(vp);
@@ -313,11 +311,11 @@ void
lfs_vcreate(struct mount *mp, ino_t ino, struct vnode *vp)
{
struct inode *ip;
struct ufs1_dinode *dp;
struct ufsmount *ump;
struct ulfs1_dinode *dp;
struct ulfsmount *ump;
/* Get a pointer to the private mount structure. */
ump = VFSTOUFS(mp);
ump = VFSTOULFS(mp);
ASSERT_NO_SEGLOCK(ump->um_lfs);
@@ -340,8 +338,8 @@ lfs_vcreate(struct mount *mp, ino_t ino, struct vnode *vp)
SPLAY_INIT(&ip->i_lfs_lbtree);
ip->i_lfs_nbtree = 0;
LIST_INIT(&ip->i_lfs_segdhd);
#ifdef QUOTA
ufsquota_init(ip);
#if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
ulfsquota_init(ip);
#endif
}
@@ -440,7 +438,6 @@ lfs_vfree(struct vnode *vp, ino_t ino, int mode)
mutex_exit(vp->v_interlock);
lfs_seglock(fs, SEGM_PROT);
vn_lock(fs->lfs_ivnode, LK_EXCLUSIVE);
lfs_unmark_vnode(vp);
mutex_enter(&lfs_lock);
@@ -553,20 +550,20 @@ lfs_vfree(struct vnode *vp, ino_t ino, int mode)
}
#endif /* DIAGNOSTIC */
if (old_iaddr != LFS_UNUSED_DADDR) {
LFS_SEGENTRY(sup, fs, dtosn(fs, old_iaddr), bp);
LFS_SEGENTRY(sup, fs, lfs_dtosn(fs, old_iaddr), bp);
#ifdef DIAGNOSTIC
if (sup->su_nbytes < sizeof (struct ufs1_dinode)) {
if (sup->su_nbytes < sizeof (struct ulfs1_dinode)) {
printf("lfs_vfree: negative byte count"
" (segment %" PRIu32 " short by %d)\n",
dtosn(fs, old_iaddr),
(int)sizeof (struct ufs1_dinode) -
lfs_dtosn(fs, old_iaddr),
(int)sizeof (struct ulfs1_dinode) -
sup->su_nbytes);
panic("lfs_vfree: negative byte count");
sup->su_nbytes = sizeof (struct ufs1_dinode);
sup->su_nbytes = sizeof (struct ulfs1_dinode);
}
#endif
sup->su_nbytes -= sizeof (struct ufs1_dinode);
LFS_WRITESEGENTRY(sup, fs, dtosn(fs, old_iaddr), bp); /* Ifile */
sup->su_nbytes -= sizeof (struct ulfs1_dinode);
LFS_WRITESEGENTRY(sup, fs, lfs_dtosn(fs, old_iaddr), bp); /* Ifile */
}
/* Set superblock modified bit and decrement file count. */
@@ -575,7 +572,6 @@ lfs_vfree(struct vnode *vp, ino_t ino, int mode)
mutex_exit(&lfs_lock);
--fs->lfs_nfiles;
VOP_UNLOCK(fs->lfs_ivnode);
lfs_segunlock(fs);
return (0);
@@ -623,10 +619,10 @@ lfs_order_freelist(struct lfs *fs)
VFS_VGET(fs->lfs_ivnode->v_mount, ino, &vp) == 0) {
lfs_truncate(vp, 0, 0, NOCRED);
vput(vp);
LFS_SEGENTRY(sup, fs, dtosn(fs, ifp->if_daddr), bp);
LFS_SEGENTRY(sup, fs, lfs_dtosn(fs, ifp->if_daddr), bp);
KASSERT(sup->su_nbytes >= DINODE1_SIZE);
sup->su_nbytes -= DINODE1_SIZE;
LFS_WRITESEGENTRY(sup, fs, dtosn(fs, ifp->if_daddr), bp);
LFS_WRITESEGENTRY(sup, fs, lfs_dtosn(fs, ifp->if_daddr), bp);
/* Set up to fall through to next section */
ifp->if_daddr = LFS_UNUSED_DADDR;
+35 -35
View File
@@ -1,4 +1,4 @@
/* $NetBSD: lfs_balloc.c,v 1.70 2011/07/11 08:27:40 hannken Exp $ */
/* $NetBSD: lfs_balloc.c,v 1.80 2013/07/28 01:25:06 dholland Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -60,7 +60,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_balloc.c,v 1.70 2011/07/11 08:27:40 hannken Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_balloc.c,v 1.80 2013/07/28 01:25:06 dholland Exp $");
#if defined(_KERNEL_OPT)
#include "opt_quota.h"
@@ -79,13 +79,14 @@ __KERNEL_RCSID(0, "$NetBSD: lfs_balloc.c,v 1.70 2011/07/11 08:27:40 hannken Exp
#include <miscfs/specfs/specdev.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/ufs_extern.h>
#include <ufs/lfs/ulfs_quotacommon.h>
#include <ufs/lfs/ulfs_inode.h>
#include <ufs/lfs/ulfsmount.h>
#include <ufs/lfs/ulfs_extern.h>
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_extern.h>
#include <ufs/lfs/lfs_kernel.h>
#include <uvm/uvm.h>
@@ -99,14 +100,14 @@ u_int64_t locked_fakequeue_count;
* this block to be created.
*
* Blocks which have never been accounted for (i.e., which "do not exist")
* have disk address 0, which is translated by ufs_bmap to the special value
* UNASSIGNED == -1, as in the historical UFS.
* have disk address 0, which is translated by ulfs_bmap to the special value
* UNASSIGNED == -1, as in the historical ULFS.
*
* Blocks which have been accounted for but which have not yet been written
* to disk are given the new special disk address UNWRITTEN == -2, so that
* they can be differentiated from completely new blocks.
*/
/* VOP_BWRITE NIADDR+2 times */
/* VOP_BWRITE ULFS_NIADDR+2 times */
int
lfs_balloc(struct vnode *vp, off_t startoffset, int iosize, kauth_cred_t cred,
int flags, struct buf **bpp)
@@ -116,16 +117,16 @@ lfs_balloc(struct vnode *vp, off_t startoffset, int iosize, kauth_cred_t cred,
struct buf *ibp, *bp;
struct inode *ip;
struct lfs *fs;
struct indir indirs[NIADDR+2], *idp;
struct indir indirs[ULFS_NIADDR+2], *idp;
daddr_t lbn, lastblock;
int bcount;
int error, frags, i, nsize, osize, num;
ip = VTOI(vp);
fs = ip->i_lfs;
offset = blkoff(fs, startoffset);
offset = lfs_blkoff(fs, startoffset);
KASSERT(iosize <= fs->lfs_bsize);
lbn = lblkno(fs, startoffset);
lbn = lfs_lblkno(fs, startoffset);
/* (void)lfs_check(vp, lbn, 0); */
ASSERT_MAYBE_SEGLOCK(fs);
@@ -150,9 +151,9 @@ lfs_balloc(struct vnode *vp, off_t startoffset, int iosize, kauth_cred_t cred,
*bpp = NULL;
/* Check for block beyond end of file and fragment extension needed. */
lastblock = lblkno(fs, ip->i_size);
if (lastblock < NDADDR && lastblock < lbn) {
osize = blksize(fs, ip, lastblock);
lastblock = lfs_lblkno(fs, ip->i_size);
if (lastblock < ULFS_NDADDR && lastblock < lbn) {
osize = lfs_blksize(fs, ip, lastblock);
if (osize < fs->lfs_bsize && osize > 0) {
if ((error = lfs_fragextend(vp, osize, fs->lfs_bsize,
lastblock,
@@ -175,12 +176,12 @@ lfs_balloc(struct vnode *vp, off_t startoffset, int iosize, kauth_cred_t cred,
* size or it already exists and contains some fragments and
* may need to extend it.
*/
if (lbn < NDADDR && lblkno(fs, ip->i_size) <= lbn) {
osize = blksize(fs, ip, lbn);
nsize = fragroundup(fs, offset + iosize);
if (lblktosize(fs, lbn) >= ip->i_size) {
if (lbn < ULFS_NDADDR && lfs_lblkno(fs, ip->i_size) <= lbn) {
osize = lfs_blksize(fs, ip, lbn);
nsize = lfs_fragroundup(fs, offset + iosize);
if (lfs_lblktosize(fs, lbn) >= ip->i_size) {
/* Brand new block or fragment */
frags = numfrags(fs, nsize);
frags = lfs_numfrags(fs, nsize);
if (!ISSPACE(fs, frags, cred))
return ENOSPC;
if (bpp) {
@@ -213,7 +214,7 @@ lfs_balloc(struct vnode *vp, off_t startoffset, int iosize, kauth_cred_t cred,
return 0;
}
error = ufs_bmaparray(vp, lbn, &daddr, &indirs[0], &num, NULL, NULL);
error = ulfs_bmaparray(vp, lbn, &daddr, &indirs[0], &num, NULL, NULL);
if (error)
return (error);
@@ -224,7 +225,7 @@ lfs_balloc(struct vnode *vp, off_t startoffset, int iosize, kauth_cred_t cred,
* Do byte accounting all at once, so we can gracefully fail *before*
* we start assigning blocks.
*/
frags = VFSTOUFS(vp->v_mount)->um_seqinc;
frags = fs->um_seqinc;
bcount = 0;
if (daddr == UNASSIGNED) {
bcount = frags;
@@ -260,7 +261,7 @@ lfs_balloc(struct vnode *vp, off_t startoffset, int iosize, kauth_cred_t cred,
clrbuf(ibp);
ibp->b_blkno = UNWRITTEN;
} else if (!(ibp->b_oflags & (BO_DELWRI | BO_DONE))) {
ibp->b_blkno = fsbtodb(fs, idaddr);
ibp->b_blkno = LFS_FSBTODB(fs, idaddr);
ibp->b_flags |= B_READ;
VOP_STRATEGY(vp, ibp);
biowait(ibp);
@@ -294,7 +295,7 @@ lfs_balloc(struct vnode *vp, off_t startoffset, int iosize, kauth_cred_t cred,
* Get the existing block from the cache, if requested.
*/
if (bpp)
*bpp = bp = getblk(vp, lbn, blksize(fs, ip, lbn), 0, 0);
*bpp = bp = getblk(vp, lbn, lfs_blksize(fs, ip, lbn), 0, 0);
/*
* Do accounting on blocks that represent pages.
@@ -306,7 +307,7 @@ lfs_balloc(struct vnode *vp, off_t startoffset, int iosize, kauth_cred_t cred,
* The block we are writing may be a brand new block
* in which case we need to do accounting.
*
* We can tell a truly new block because ufs_bmaparray will say
* We can tell a truly new block because ulfs_bmaparray will say
* it is UNASSIGNED. Once we allocate it we will assign it the
* disk address UNWRITTEN.
*/
@@ -380,7 +381,7 @@ lfs_fragextend(struct vnode *vp, int osize, int nsize, daddr_t lbn, struct buf *
ip = VTOI(vp);
fs = ip->i_lfs;
frags = (long)numfrags(fs, nsize - osize);
frags = (long)lfs_numfrags(fs, nsize - osize);
error = 0;
ASSERT_NO_SEGLOCK(fs);
@@ -409,11 +410,10 @@ lfs_fragextend(struct vnode *vp, int osize, int nsize, daddr_t lbn, struct buf *
* Don't bother to read in that case.
*/
if (bpp && (error = bread(vp, lbn, osize, NOCRED, 0, bpp))) {
brelse(*bpp, 0);
goto out;
}
#ifdef QUOTA
if ((error = chkdq(ip, frags, cred, 0))) {
#if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
if ((error = lfs_chkdq(ip, frags, cred, 0))) {
if (bpp)
brelse(*bpp, 0);
goto out;
@@ -430,8 +430,8 @@ lfs_fragextend(struct vnode *vp, int osize, int nsize, daddr_t lbn, struct buf *
if (!lfs_fits(fs, frags)) {
if (bpp)
brelse(*bpp, 0);
#ifdef QUOTA
chkdq(ip, -frags, cred, 0);
#if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
lfs_chkdq(ip, -frags, cred, 0);
#endif
rw_exit(&fs->lfs_fraglock);
lfs_availwait(fs, frags);
@@ -501,7 +501,7 @@ lfs_register_block(struct vnode *vp, daddr_t lbn)
ASSERT_NO_SEGLOCK(fs);
/* If no space, wait for the cleaner */
lfs_availwait(fs, btofsb(fs, 1 << fs->lfs_bshift));
lfs_availwait(fs, lfs_btofsb(fs, 1 << fs->lfs_bshift));
lbp = (struct lbnentry *)pool_get(&lfs_lbnentry_pool, PR_WAITOK);
lbp->lbn = lbn;
@@ -514,7 +514,7 @@ lfs_register_block(struct vnode *vp, daddr_t lbn)
}
++ip->i_lfs_nbtree;
fs->lfs_favail += btofsb(fs, (1 << fs->lfs_bshift));
fs->lfs_favail += lfs_btofsb(fs, (1 << fs->lfs_bshift));
fs->lfs_pages += fs->lfs_bsize >> PAGE_SHIFT;
++locked_fakequeue_count;
lfs_subsys_pages += fs->lfs_bsize >> PAGE_SHIFT;
@@ -529,8 +529,8 @@ lfs_do_deregister(struct lfs *fs, struct inode *ip, struct lbnentry *lbp)
mutex_enter(&lfs_lock);
--ip->i_lfs_nbtree;
SPLAY_REMOVE(lfs_splay, &ip->i_lfs_lbtree, lbp);
if (fs->lfs_favail > btofsb(fs, (1 << fs->lfs_bshift)))
fs->lfs_favail -= btofsb(fs, (1 << fs->lfs_bshift));
if (fs->lfs_favail > lfs_btofsb(fs, (1 << fs->lfs_bshift)))
fs->lfs_favail -= lfs_btofsb(fs, (1 << fs->lfs_bshift));
fs->lfs_pages -= fs->lfs_bsize >> PAGE_SHIFT;
if (locked_fakequeue_count > 0)
--locked_fakequeue_count;
+49 -65
View File
@@ -1,4 +1,4 @@
/* $NetBSD: lfs_bio.c,v 1.120 2011/07/11 08:27:40 hannken Exp $ */
/* $NetBSD: lfs_bio.c,v 1.128 2013/11/27 17:24:44 christos Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003, 2008 The NetBSD Foundation, Inc.
@@ -60,7 +60,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_bio.c,v 1.120 2011/07/11 08:27:40 hannken Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_bio.c,v 1.128 2013/11/27 17:24:44 christos Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -72,12 +72,13 @@ __KERNEL_RCSID(0, "$NetBSD: lfs_bio.c,v 1.120 2011/07/11 08:27:40 hannken Exp $"
#include <sys/kernel.h>
#include <sys/kauth.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/ufs_extern.h>
#include <ufs/lfs/ulfs_inode.h>
#include <ufs/lfs/ulfsmount.h>
#include <ufs/lfs/ulfs_extern.h>
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_extern.h>
#include <ufs/lfs/lfs_kernel.h>
#include <uvm/uvm.h>
@@ -96,6 +97,7 @@ int lfs_subsys_pages = 0L; /* Total number LFS-written pages */
int lfs_fs_pagetrip = 0; /* # of pages to trip per-fs write */
int lfs_writing = 0; /* Set if already kicked off a writer
because of buffer space */
int locked_queue_waiters = 0; /* Number of processes waiting on lq */
/* Lock and condition variables for above. */
kcondvar_t locked_queue_cv;
@@ -150,18 +152,25 @@ static int
lfs_reservebuf(struct lfs *fs, struct vnode *vp,
struct vnode *vp2, int n, int bytes)
{
int cantwait;
ASSERT_MAYBE_SEGLOCK(fs);
KASSERT(locked_queue_rcount >= 0);
KASSERT(locked_queue_rbytes >= 0);
cantwait = (VTOI(vp)->i_flag & IN_ADIROP) || fs->lfs_unlockvp == vp;
mutex_enter(&lfs_lock);
while (n > 0 && !lfs_fits_buf(fs, n, bytes)) {
while (!cantwait && n > 0 && !lfs_fits_buf(fs, n, bytes)) {
int error;
lfs_flush(fs, 0, 0);
DLOG((DLOG_AVAIL, "lfs_reservebuf: waiting: count=%d, bytes=%ld\n",
locked_queue_count, locked_queue_bytes));
++locked_queue_waiters;
error = cv_timedwait_sig(&locked_queue_cv, &lfs_lock,
hz * LFS_BUFWAIT);
--locked_queue_waiters;
if (error && error != EWOULDBLOCK) {
mutex_exit(&lfs_lock);
return error;
@@ -171,8 +180,11 @@ lfs_reservebuf(struct lfs *fs, struct vnode *vp,
locked_queue_rcount += n;
locked_queue_rbytes += bytes;
if (n < 0)
if (n < 0 && locked_queue_waiters > 0) {
DLOG((DLOG_AVAIL, "lfs_reservebuf: broadcast: count=%d, bytes=%ld\n",
locked_queue_count, locked_queue_bytes));
cv_broadcast(&locked_queue_cv);
}
mutex_exit(&lfs_lock);
@@ -205,28 +217,15 @@ lfs_reserveavail(struct lfs *fs, struct vnode *vp,
CLEANERINFO *cip;
struct buf *bp;
int error, slept;
int cantwait;
ASSERT_MAYBE_SEGLOCK(fs);
slept = 0;
mutex_enter(&lfs_lock);
while (fsb > 0 && !lfs_fits(fs, fsb + fs->lfs_ravail + fs->lfs_favail)) {
cantwait = (VTOI(vp)->i_flag & IN_ADIROP) || fs->lfs_unlockvp == vp;
while (!cantwait && fsb > 0 &&
!lfs_fits(fs, fsb + fs->lfs_ravail + fs->lfs_favail)) {
mutex_exit(&lfs_lock);
#if 0
/*
* XXX ideally, we should unlock vnodes here
* because we might sleep very long time.
*/
VOP_UNLOCK(vp);
if (vp2 != NULL) {
VOP_UNLOCK(vp2);
}
#else
/*
* XXX since we'll sleep for cleaner with vnode lock holding,
* deadlock will occur if cleaner tries to lock the vnode.
* (eg. lfs_markv -> lfs_fastvget -> getnewvnode -> vclean)
*/
#endif
if (!slept) {
DLOG((DLOG_AVAIL, "lfs_reserve: waiting for %ld (bfree = %d,"
@@ -248,10 +247,6 @@ lfs_reserveavail(struct lfs *fs, struct vnode *vp,
error = mtsleep(&fs->lfs_avail, PCATCH | PUSER, "lfs_reserve",
0, &lfs_lock);
#if 0
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); /* XXX use lockstatus */
vn_lock(vp2, LK_EXCLUSIVE | LK_RETRY); /* XXX use lockstatus */
#endif
if (error) {
mutex_exit(&lfs_lock);
return error;
@@ -277,7 +272,6 @@ int
lfs_reserve(struct lfs *fs, struct vnode *vp, struct vnode *vp2, int fsb)
{
int error;
int cantwait;
ASSERT_MAYBE_SEGLOCK(fs);
if (vp2) {
@@ -292,30 +286,18 @@ lfs_reserve(struct lfs *fs, struct vnode *vp, struct vnode *vp2, int fsb)
KASSERT(fsb < 0 || VOP_ISLOCKED(vp));
KASSERT(vp2 == NULL || fsb < 0 || VOP_ISLOCKED(vp2));
KASSERT(vp2 == NULL || !(VTOI(vp2)->i_flag & IN_ADIROP));
KASSERT(vp2 == NULL || vp2 != fs->lfs_unlockvp);
cantwait = (VTOI(vp)->i_flag & IN_ADIROP) || fs->lfs_unlockvp == vp;
#ifdef DIAGNOSTIC
if (cantwait) {
if (fsb > 0)
lfs_rescountdirop++;
else if (fsb < 0)
lfs_rescountdirop--;
if (lfs_rescountdirop < 0)
panic("lfs_rescountdirop");
}
else {
if (fsb > 0)
lfs_rescount++;
else if (fsb < 0)
lfs_rescount--;
if (lfs_rescount < 0)
panic("lfs_rescount");
}
mutex_enter(&lfs_lock);
if (fsb > 0)
lfs_rescount++;
else if (fsb < 0)
lfs_rescount--;
if (lfs_rescount < 0)
panic("lfs_rescount");
mutex_exit(&lfs_lock);
#endif
if (cantwait)
return 0;
/*
* XXX
@@ -334,7 +316,7 @@ lfs_reserve(struct lfs *fs, struct vnode *vp, struct vnode *vp2, int fsb)
/*
* XXX just a guess. should be more precise.
*/
error = lfs_reservebuf(fs, vp, vp2, fsb, fsbtob(fs, fsb));
error = lfs_reservebuf(fs, vp, vp2, fsb, lfs_fsbtob(fs, fsb));
if (error)
lfs_reserveavail(fs, vp, vp2, -fsb);
@@ -376,8 +358,8 @@ lfs_fits(struct lfs *fs, int fsb)
int needed;
ASSERT_NO_SEGLOCK(fs);
needed = fsb + btofsb(fs, fs->lfs_sumsize) +
((howmany(fs->lfs_uinodes + 1, INOPB(fs)) + fs->lfs_segtabsz +
needed = fsb + lfs_btofsb(fs, fs->lfs_sumsize) +
((howmany(fs->lfs_uinodes + 1, LFS_INOPB(fs)) + fs->lfs_segtabsz +
1) << (fs->lfs_bshift - fs->lfs_ffshift));
if (needed >= fs->lfs_avail) {
@@ -445,7 +427,7 @@ lfs_bwrite_ext(struct buf *bp, int flags)
int fsb;
vp = bp->b_vp;
fs = VFSTOUFS(vp->v_mount)->um_lfs;
fs = VFSTOULFS(vp->v_mount)->um_lfs;
ASSERT_MAYBE_SEGLOCK(fs);
KASSERT(bp->b_cflags & BC_BUSY);
@@ -461,7 +443,7 @@ lfs_bwrite_ext(struct buf *bp, int flags)
*/
if (fs->lfs_ronly || (fs->lfs_pflags & LFS_PF_CLEAN)) {
bp->b_oflags &= ~BO_DELWRI;
bp->b_flags |= B_READ;
bp->b_flags |= B_READ; /* XXX is this right? --ks */
bp->b_error = 0;
mutex_enter(&bufcache_lock);
LFS_UNLOCK_BUF(bp);
@@ -488,7 +470,7 @@ lfs_bwrite_ext(struct buf *bp, int flags)
* blocks.
*/
if ((bp->b_flags & B_LOCKED) == 0) {
fsb = numfrags(fs, bp->b_bcount);
fsb = lfs_numfrags(fs, bp->b_bcount);
ip = VTOI(vp);
mutex_enter(&lfs_lock);
@@ -535,6 +517,7 @@ lfs_flush_fs(struct lfs *fs, int flags)
if (lfs_dostats)
++lfs_stats.flush_invoked;
fs->lfs_pdflush = 0;
mutex_exit(&lfs_lock);
lfs_writer_enter(fs, "fldirop");
lfs_segwrite(fs->lfs_ivnode->v_mount, flags);
@@ -587,15 +570,14 @@ lfs_flush(struct lfs *fs, int flags, int only_onefs)
} else {
locked_fakequeue_count = 0;
mutex_enter(&mountlist_lock);
for (mp = CIRCLEQ_FIRST(&mountlist); mp != (void *)&mountlist;
mp = nmp) {
for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
if (vfs_busy(mp, &nmp)) {
DLOG((DLOG_FLUSH, "lfs_flush: fs vfs_busy\n"));
continue;
}
if (strncmp(&mp->mnt_stat.f_fstypename[0], MOUNT_LFS,
sizeof(mp->mnt_stat.f_fstypename)) == 0) {
tfs = VFSTOUFS(mp)->um_lfs;
tfs = VFSTOULFS(mp)->um_lfs;
mutex_enter(&lfs_lock);
lfs_flush_fs(tfs, flags);
mutex_exit(&lfs_lock);
@@ -614,8 +596,8 @@ lfs_flush(struct lfs *fs, int flags, int only_onefs)
wakeup(&lfs_writing);
}
#define INOCOUNT(fs) howmany((fs)->lfs_uinodes, INOPB(fs))
#define INOBYTES(fs) ((fs)->lfs_uinodes * sizeof (struct ufs1_dinode))
#define INOCOUNT(fs) howmany((fs)->lfs_uinodes, LFS_INOPB(fs))
#define INOBYTES(fs) ((fs)->lfs_uinodes * sizeof (struct ulfs1_dinode))
/*
* make sure that we don't have too many locked buffers.
@@ -689,10 +671,10 @@ lfs_check(struct vnode *vp, daddr_t blkno, int flags)
/* If there are too many pending dirops, we have to flush them. */
if (fs->lfs_dirvcount > LFS_MAX_FSDIROP(fs) ||
lfs_dirvcount > LFS_MAX_DIROP || fs->lfs_diropwait > 0) {
flags |= SEGM_CKP;
}
if (locked_queue_count + INOCOUNT(fs) > LFS_MAX_BUFS ||
mutex_exit(&lfs_lock);
lfs_flush_dirops(fs);
mutex_enter(&lfs_lock);
} else if (locked_queue_count + INOCOUNT(fs) > LFS_MAX_BUFS ||
locked_queue_bytes + INOBYTES(fs) > LFS_MAX_BYTES ||
lfs_subsys_pages > LFS_MAX_PAGES ||
fs->lfs_dirvcount > LFS_MAX_FSDIROP(fs) ||
@@ -717,8 +699,10 @@ lfs_check(struct vnode *vp, daddr_t blkno, int flags)
++lfs_stats.wait_exceeded;
DLOG((DLOG_AVAIL, "lfs_check: waiting: count=%d, bytes=%ld\n",
locked_queue_count, locked_queue_bytes));
++locked_queue_waiters;
error = cv_timedwait_sig(&locked_queue_cv, &lfs_lock,
hz * LFS_BUFWAIT);
--locked_queue_waiters;
if (error != EWOULDBLOCK)
break;
@@ -747,7 +731,7 @@ lfs_newbuf(struct lfs *fs, struct vnode *vp, daddr_t daddr, size_t size, int typ
size_t nbytes;
ASSERT_MAYBE_SEGLOCK(fs);
nbytes = roundup(size, fsbtob(fs, 1));
nbytes = roundup(size, lfs_fsbtob(fs, 1));
bp = getiobuf(NULL, true);
if (nbytes) {
+2 -3
View File
@@ -1,4 +1,4 @@
/* $NetBSD: lfs_cksum.c,v 1.27 2008/04/28 20:24:11 martin Exp $ */
/* $NetBSD: lfs_cksum.c,v 1.29 2013/06/06 00:54:49 dholland Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002 The NetBSD Foundation, Inc.
@@ -60,7 +60,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_cksum.c,v 1.27 2008/04/28 20:24:11 martin Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_cksum.c,v 1.29 2013/06/06 00:54:49 dholland Exp $");
#include <sys/param.h>
#ifdef _KERNEL
@@ -70,7 +70,6 @@ __KERNEL_RCSID(0, "$NetBSD: lfs_cksum.c,v 1.27 2008/04/28 20:24:11 martin Exp $"
# include <stddef.h>
#endif
#include <sys/mount.h>
#include <ufs/ufs/inode.h>
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_extern.h>
+9 -9
View File
@@ -1,4 +1,4 @@
/* $NetBSD: lfs_debug.c,v 1.39 2011/07/17 20:54:54 joerg Exp $ */
/* $NetBSD: lfs_debug.c,v 1.43 2013/06/18 18:18:58 christos Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -60,7 +60,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_debug.c,v 1.39 2011/07/17 20:54:54 joerg Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_debug.c,v 1.43 2013/06/18 18:18:58 christos Exp $");
#ifdef DEBUG
@@ -73,7 +73,7 @@ __KERNEL_RCSID(0, "$NetBSD: lfs_debug.c,v 1.39 2011/07/17 20:54:54 joerg Exp $")
#include <sys/syslog.h>
#include <sys/proc.h>
#include <ufs/ufs/inode.h>
#include <ufs/lfs/ulfs_inode.h>
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_extern.h>
@@ -188,7 +188,7 @@ lfs_dump_super(struct lfs *lfsp)
}
void
lfs_dump_dinode(struct ufs1_dinode *dip)
lfs_dump_dinode(struct ulfs1_dinode *dip)
{
int i;
@@ -201,12 +201,12 @@ lfs_dump_dinode(struct ufs1_dinode *dip)
"blocks ", dip->di_blocks);
printf("inum %d\n", dip->di_inumber);
printf("Direct Addresses\n");
for (i = 0; i < NDADDR; i++) {
for (i = 0; i < ULFS_NDADDR; i++) {
printf("\t%x", dip->di_db[i]);
if ((i % 6) == 5)
printf("\n");
}
for (i = 0; i < NIADDR; i++)
for (i = 0; i < ULFS_NIADDR; i++)
printf("\t%x", dip->di_ib[i]);
printf("\n");
}
@@ -240,7 +240,7 @@ lfs_check_segsum(struct lfs *fs, struct segment *sp, char *file, int line)
/* amount taken up by FINFOs */
- ((char *)&(sp->fip->fi_blocks[sp->fip->fi_nblocks]) - (char *)(sp->segsum))
/* amount taken up by inode blocks */
- sizeof(int32_t)*((sp->ninodes+INOPB(fs)-1) / INOPB(fs));
- sizeof(int32_t)*((sp->ninodes+LFS_INOPB(fs)-1) / LFS_INOPB(fs));
#if 0
if (actual - sp->sum_bytes_left < offset)
{
@@ -259,7 +259,7 @@ lfs_check_segsum(struct lfs *fs, struct segment *sp, char *file, int line)
#endif
if (sp->sum_bytes_left > 0
&& ((char *)(sp->segsum))[fs->lfs_sumsize
- sizeof(int32_t) * ((sp->ninodes+INOPB(fs)-1) / INOPB(fs))
- sizeof(int32_t) * ((sp->ninodes+LFS_INOPB(fs)-1) / LFS_INOPB(fs))
- sp->sum_bytes_left] != '\0') {
printf("%s:%d: warning: segsum overwrite at %d (-%d => %d)\n",
file, line, sp->sum_bytes_left,
@@ -299,7 +299,7 @@ lfs_check_bpp(struct lfs *fs, struct segment *sp, char *file, int line)
(*bpp)->b_blkno);
}
}
blkno += fsbtodb(fs, btofsb(fs, (*bpp)->b_bcount));
blkno += LFS_FSBTODB(fs, lfs_btofsb(fs, (*bpp)->b_bcount));
}
}
+12 -8
View File
@@ -1,4 +1,4 @@
/* $NetBSD: lfs_extern.h,v 1.96 2008/06/28 01:34:05 rumble Exp $ */
/* $NetBSD: lfs_extern.h,v 1.100 2013/07/20 19:59:31 dholland Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -94,7 +94,7 @@ struct timeval;
struct inode;
struct uio;
struct mbuf;
struct ufs1_dinode;
struct ulfs1_dinode;
struct buf;
struct vnode;
struct dlfs;
@@ -102,6 +102,8 @@ struct lfs;
struct segment;
struct block_info;
__BEGIN_DECLS
#if defined(_KERNEL)
extern int lfs_allclean_wakeup;
@@ -119,7 +121,6 @@ extern int lfs_debug_log_subsys[];
extern kcondvar_t lfs_writing_cv;
extern kcondvar_t locked_queue_cv;
__BEGIN_DECLS
/* lfs_alloc.c */
void lfs_vcreate(struct mount *, ino_t, struct vnode *);
int lfs_valloc(struct vnode *, int, kauth_cred_t, struct vnode **);
@@ -152,7 +153,7 @@ int lfs_reserve(struct lfs *, struct vnode *, struct vnode *, int);
int lfs_bwrite_log(struct buf *, const char *, int);
void lfs_dumplog(void);
void lfs_dump_super(struct lfs *);
void lfs_dump_dinode(struct ufs1_dinode *);
void lfs_dump_dinode(struct ulfs1_dinode *);
void lfs_check_bpp(struct lfs *, struct segment *, char *, int);
void lfs_check_segsum(struct lfs *, struct segment *, char *, int);
void lfs_debug_log(int, const char *, ...);
@@ -162,10 +163,13 @@ void lfs_debug_log(int, const char *, ...);
int lfs_update(struct vnode *, const struct timespec *, const struct timespec *,
int);
int lfs_truncate(struct vnode *, off_t, int, kauth_cred_t);
struct ufs1_dinode *lfs_ifind(struct lfs *, ino_t, struct buf *);
struct ulfs1_dinode *lfs_ifind(struct lfs *, ino_t, struct buf *);
void lfs_finalize_ino_seguse(struct lfs *, struct inode *);
void lfs_finalize_fs_seguse(struct lfs *);
/* lfs_rename.c */
int lfs_rename(void *);
/* lfs_rfw.c */
int lfs_rf_valloc(struct lfs *, ino_t, int, struct lwp *, struct vnode **);
void lfs_roll_forward(struct lfs *, struct mount *, struct lwp *);
@@ -211,7 +215,7 @@ void lfs_writer_leave(struct lfs *);
void lfs_wakeup_cleaner(struct lfs *);
/* lfs_syscalls.c */
int lfs_fastvget(struct mount *, ino_t, daddr_t, struct vnode **, struct ufs1_dinode *);
int lfs_fastvget(struct mount *, ino_t, daddr_t, struct vnode **, struct ulfs1_dinode *);
struct buf *lfs_fakebuf(struct lfs *, struct vnode *, int, size_t, void *);
int lfs_do_segclean(struct lfs *, unsigned long);
int lfs_segwait(fsid_t *, struct timeval *);
@@ -240,8 +244,8 @@ int lfs_gop_alloc(struct vnode *, off_t, off_t, int, kauth_cred_t);
void lfs_gop_size(struct vnode *, off_t, off_t *, int);
int lfs_putpages_ext(void *, int);
int lfs_gatherpages(struct vnode *);
void lfs_flush_dirops(struct lfs *);
void lfs_flush_pchain(struct lfs *);
int lfs_flush_dirops(struct lfs *);
int lfs_flush_pchain(struct lfs *);
int lfs_bwrite (void *);
int lfs_fsync (void *);
+81 -82
View File
@@ -1,4 +1,4 @@
/* $NetBSD: lfs_inode.c,v 1.126 2011/11/23 19:42:10 bouyer Exp $ */
/* $NetBSD: lfs_inode.c,v 1.136 2013/10/17 21:01:08 christos Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -60,7 +60,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_inode.c,v 1.126 2011/11/23 19:42:10 bouyer Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_inode.c,v 1.136 2013/10/17 21:01:08 christos Exp $");
#if defined(_KERNEL_OPT)
#include "opt_quota.h"
@@ -79,13 +79,14 @@ __KERNEL_RCSID(0, "$NetBSD: lfs_inode.c,v 1.126 2011/11/23 19:42:10 bouyer Exp $
#include <sys/resourcevar.h>
#include <sys/kauth.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/ufs_extern.h>
#include <ufs/lfs/ulfs_quotacommon.h>
#include <ufs/lfs/ulfs_inode.h>
#include <ufs/lfs/ulfsmount.h>
#include <ufs/lfs/ulfs_extern.h>
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_extern.h>
#include <ufs/lfs/lfs_kernel.h>
static int lfs_update_seguse(struct lfs *, struct inode *ip, long, size_t);
static int lfs_indirtrunc (struct inode *, daddr_t, daddr_t,
@@ -94,11 +95,11 @@ static int lfs_blkfree (struct lfs *, struct inode *, daddr_t, size_t, long *, s
static int lfs_vtruncbuf(struct vnode *, daddr_t, bool, int);
/* Search a block for a specific dinode. */
struct ufs1_dinode *
struct ulfs1_dinode *
lfs_ifind(struct lfs *fs, ino_t ino, struct buf *bp)
{
struct ufs1_dinode *dip = (struct ufs1_dinode *)bp->b_data;
struct ufs1_dinode *ldip, *fin;
struct ulfs1_dinode *dip = (struct ulfs1_dinode *)bp->b_data;
struct ulfs1_dinode *ldip, *fin;
ASSERT_NO_SEGLOCK(fs);
/*
@@ -106,17 +107,17 @@ lfs_ifind(struct lfs *fs, ino_t ino, struct buf *bp)
* inode will supercede earlier ones. Though it is unlikely, it is
* possible that the same inode will appear in the same inode block.
*/
fin = dip + INOPB(fs);
fin = dip + LFS_INOPB(fs);
for (ldip = fin - 1; ldip >= dip; --ldip)
if (ldip->di_inumber == ino)
return (ldip);
printf("searched %d entries\n", (int)(fin - dip));
printf("offset is 0x%x (seg %d)\n", fs->lfs_offset,
dtosn(fs, fs->lfs_offset));
lfs_dtosn(fs, fs->lfs_offset));
printf("block is 0x%llx (seg %lld)\n",
(unsigned long long)dbtofsb(fs, bp->b_blkno),
(long long)dtosn(fs, dbtofsb(fs, bp->b_blkno)));
(unsigned long long)LFS_DBTOFSB(fs, bp->b_blkno),
(long long)lfs_dtosn(fs, LFS_DBTOFSB(fs, bp->b_blkno)));
return NULL;
}
@@ -126,7 +127,7 @@ lfs_update(struct vnode *vp, const struct timespec *acc,
const struct timespec *mod, int updflags)
{
struct inode *ip;
struct lfs *fs = VFSTOUFS(vp->v_mount)->um_lfs;
struct lfs *fs = VFSTOULFS(vp->v_mount)->um_lfs;
int flags;
ASSERT_NO_SEGLOCK(fs);
@@ -191,16 +192,16 @@ lfs_update(struct vnode *vp, const struct timespec *acc,
* Truncate the inode oip to at most length size, freeing the
* disk blocks.
*/
/* VOP_BWRITE 1 + NIADDR + lfs_balloc == 2 + 2*NIADDR times */
/* VOP_BWRITE 1 + ULFS_NIADDR + lfs_balloc == 2 + 2*ULFS_NIADDR times */
int
lfs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
{
daddr_t lastblock;
struct inode *oip = VTOI(ovp);
daddr_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR];
daddr_t bn, lbn, lastiblock[ULFS_NIADDR], indir_lbn[ULFS_NIADDR];
/* XXX ondisk32 */
int32_t newblks[NDADDR + NIADDR];
int32_t newblks[ULFS_NDADDR + ULFS_NIADDR];
struct lfs *fs;
struct buf *bp;
int offset, size, level;
@@ -212,7 +213,6 @@ lfs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
size_t bc;
int obufsize, odb;
int usepc;
struct ufsmount *ump = oip->i_ump;
if (ovp->v_type == VCHR || ovp->v_type == VBLK ||
ovp->v_type == VFIFO || ovp->v_type == VSOCK) {
@@ -232,9 +232,11 @@ lfs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
return (0);
}
fs = oip->i_lfs;
if (ovp->v_type == VLNK &&
(oip->i_size < ump->um_maxsymlinklen ||
(ump->um_maxsymlinklen == 0 &&
(oip->i_size < fs->um_maxsymlinklen ||
(fs->um_maxsymlinklen == 0 &&
oip->i_ffs1_blocks == 0))) {
#ifdef DIAGNOSTIC
if (length != 0)
@@ -249,7 +251,6 @@ lfs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
oip->i_flag |= IN_CHANGE | IN_UPDATE;
return (lfs_update(ovp, NULL, NULL, 0));
}
fs = oip->i_lfs;
lfs_imtime(fs);
osize = oip->i_size;
usepc = (ovp->v_type == VREG && ovp != fs->lfs_ivnode);
@@ -261,20 +262,20 @@ lfs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
* value of osize is 0, length will be at least 1.
*/
if (osize < length) {
if (length > ump->um_maxfilesize)
if (length > fs->um_maxfilesize)
return (EFBIG);
aflags = B_CLRBUF;
if (ioflag & IO_SYNC)
aflags |= B_SYNC;
if (usepc) {
if (lblkno(fs, osize) < NDADDR &&
lblkno(fs, osize) != lblkno(fs, length) &&
blkroundup(fs, osize) != osize) {
if (lfs_lblkno(fs, osize) < ULFS_NDADDR &&
lfs_lblkno(fs, osize) != lfs_lblkno(fs, length) &&
lfs_blkroundup(fs, osize) != osize) {
off_t eob;
eob = blkroundup(fs, osize);
eob = lfs_blkroundup(fs, osize);
uvm_vnp_setwritesize(ovp, eob);
error = ufs_balloc_range(ovp, osize,
error = ulfs_balloc_range(ovp, osize,
eob - osize, cred, aflags);
if (error) {
(void) lfs_truncate(ovp, osize,
@@ -290,7 +291,7 @@ lfs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
}
}
uvm_vnp_setwritesize(ovp, length);
error = ufs_balloc_range(ovp, length - 1, 1, cred,
error = ulfs_balloc_range(ovp, length - 1, 1, cred,
aflags);
if (error) {
(void) lfs_truncate(ovp, osize,
@@ -300,30 +301,30 @@ lfs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
uvm_vnp_setsize(ovp, length);
oip->i_flag |= IN_CHANGE | IN_UPDATE;
KASSERT(ovp->v_size == oip->i_size);
oip->i_lfs_hiblk = lblkno(fs, oip->i_size + fs->lfs_bsize - 1) - 1;
oip->i_lfs_hiblk = lfs_lblkno(fs, oip->i_size + fs->lfs_bsize - 1) - 1;
return (lfs_update(ovp, NULL, NULL, 0));
} else {
error = lfs_reserve(fs, ovp, NULL,
btofsb(fs, (NIADDR + 2) << fs->lfs_bshift));
lfs_btofsb(fs, (ULFS_NIADDR + 2) << fs->lfs_bshift));
if (error)
return (error);
error = lfs_balloc(ovp, length - 1, 1, cred,
aflags, &bp);
lfs_reserve(fs, ovp, NULL,
-btofsb(fs, (NIADDR + 2) << fs->lfs_bshift));
-lfs_btofsb(fs, (ULFS_NIADDR + 2) << fs->lfs_bshift));
if (error)
return (error);
oip->i_ffs1_size = oip->i_size = length;
uvm_vnp_setsize(ovp, length);
(void) VOP_BWRITE(bp->b_vp, bp);
oip->i_flag |= IN_CHANGE | IN_UPDATE;
oip->i_lfs_hiblk = lblkno(fs, oip->i_size + fs->lfs_bsize - 1) - 1;
oip->i_lfs_hiblk = lfs_lblkno(fs, oip->i_size + fs->lfs_bsize - 1) - 1;
return (lfs_update(ovp, NULL, NULL, 0));
}
}
if ((error = lfs_reserve(fs, ovp, NULL,
btofsb(fs, (2 * NIADDR + 3) << fs->lfs_bshift))) != 0)
lfs_btofsb(fs, (2 * ULFS_NIADDR + 3) << fs->lfs_bshift))) != 0)
return (error);
/*
@@ -334,7 +335,7 @@ lfs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
* of subsequent file growth. Directories however are not
* zero'ed as they should grow back initialized to empty.
*/
offset = blkoff(fs, length);
offset = lfs_blkoff(fs, length);
lastseg = -1;
bc = 0;
@@ -343,20 +344,20 @@ lfs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
if (offset == 0) {
oip->i_size = oip->i_ffs1_size = length;
} else if (!usepc) {
lbn = lblkno(fs, length);
lbn = lfs_lblkno(fs, length);
aflags = B_CLRBUF;
if (ioflag & IO_SYNC)
aflags |= B_SYNC;
error = lfs_balloc(ovp, length - 1, 1, cred, aflags, &bp);
if (error) {
lfs_reserve(fs, ovp, NULL,
-btofsb(fs, (2 * NIADDR + 3) << fs->lfs_bshift));
-lfs_btofsb(fs, (2 * ULFS_NIADDR + 3) << fs->lfs_bshift));
goto errout;
}
obufsize = bp->b_bufsize;
odb = btofsb(fs, bp->b_bcount);
odb = lfs_btofsb(fs, bp->b_bcount);
oip->i_size = oip->i_ffs1_size = length;
size = blksize(fs, oip, lbn);
size = lfs_blksize(fs, oip, lbn);
if (ovp->v_type != VDIR)
memset((char *)bp->b_data + offset, 0,
(u_int)(size - offset));
@@ -367,7 +368,7 @@ lfs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
mutex_exit(&lfs_lock);
}
if (bp->b_oflags & BO_DELWRI)
fs->lfs_avail += odb - btofsb(fs, size);
fs->lfs_avail += odb - lfs_btofsb(fs, size);
(void) VOP_BWRITE(bp->b_vp, bp);
} else { /* vp->v_type == VREG && length < osize && offset != 0 */
/*
@@ -385,15 +386,15 @@ lfs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
voff_t eoz;
aflags = ioflag & IO_SYNC ? B_SYNC : 0;
error = ufs_balloc_range(ovp, length - 1, 1, cred, aflags);
error = ulfs_balloc_range(ovp, length - 1, 1, cred, aflags);
if (error) {
lfs_reserve(fs, ovp, NULL,
-btofsb(fs, (2 * NIADDR + 3) << fs->lfs_bshift));
-lfs_btofsb(fs, (2 * ULFS_NIADDR + 3) << fs->lfs_bshift));
goto errout;
}
xlbn = lblkno(fs, length);
size = blksize(fs, oip, xlbn);
eoz = MIN(lblktosize(fs, xlbn) + size, osize);
xlbn = lfs_lblkno(fs, length);
size = lfs_blksize(fs, oip, xlbn);
eoz = MIN(lfs_lblktosize(fs, xlbn) + size, osize);
ubc_zerorange(&ovp->v_uobj, length, eoz - length,
UBC_UNMAP_FLAG(ovp));
if (round_page(eoz) > round_page(length)) {
@@ -404,7 +405,7 @@ lfs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
((ioflag & IO_SYNC) ? PGO_SYNCIO : 0));
if (error) {
lfs_reserve(fs, ovp, NULL,
-btofsb(fs, (2 * NIADDR + 3) << fs->lfs_bshift));
-lfs_btofsb(fs, (2 * ULFS_NIADDR + 3) << fs->lfs_bshift));
goto errout;
}
}
@@ -423,13 +424,13 @@ lfs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
*/
/* Avoid sign overflow - XXX assumes that off_t is a quad_t. */
if (length > QUAD_MAX - fs->lfs_bsize)
lastblock = lblkno(fs, QUAD_MAX - fs->lfs_bsize);
lastblock = lfs_lblkno(fs, QUAD_MAX - fs->lfs_bsize);
else
lastblock = lblkno(fs, length + fs->lfs_bsize - 1) - 1;
lastiblock[SINGLE] = lastblock - NDADDR;
lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
nblocks = btofsb(fs, fs->lfs_bsize);
lastblock = lfs_lblkno(fs, length + fs->lfs_bsize - 1) - 1;
lastiblock[SINGLE] = lastblock - ULFS_NDADDR;
lastiblock[DOUBLE] = lastiblock[SINGLE] - LFS_NINDIR(fs);
lastiblock[TRIPLE] = lastiblock[DOUBLE] - LFS_NINDIR(fs) * LFS_NINDIR(fs);
nblocks = lfs_btofsb(fs, fs->lfs_bsize);
/*
* Record changed file and block pointers before we start
* freeing blocks. lastiblock values are also normalized to -1
@@ -438,10 +439,10 @@ lfs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
memcpy((void *)newblks, (void *)&oip->i_ffs1_db[0], sizeof newblks);
for (level = TRIPLE; level >= SINGLE; level--)
if (lastiblock[level] < 0) {
newblks[NDADDR+level] = 0;
newblks[ULFS_NDADDR+level] = 0;
lastiblock[level] = -1;
}
for (i = NDADDR - 1; i > lastblock; i--)
for (i = ULFS_NDADDR - 1; i > lastblock; i--)
newblks[i] = 0;
oip->i_size = oip->i_ffs1_size = osize;
@@ -452,9 +453,9 @@ lfs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
/*
* Indirect blocks first.
*/
indir_lbn[SINGLE] = -NDADDR;
indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) - 1;
indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1;
indir_lbn[SINGLE] = -ULFS_NDADDR;
indir_lbn[DOUBLE] = indir_lbn[SINGLE] - LFS_NINDIR(fs) - 1;
indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - LFS_NINDIR(fs) * LFS_NINDIR(fs) - 1;
for (level = TRIPLE; level >= SINGLE; level--) {
bn = oip->i_ffs1_ib[level];
if (bn != 0) {
@@ -483,21 +484,21 @@ lfs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
/*
* All whole direct blocks or frags.
*/
for (i = NDADDR - 1; i > lastblock; i--) {
for (i = ULFS_NDADDR - 1; i > lastblock; i--) {
long bsize, obsize;
bn = oip->i_ffs1_db[i];
if (bn == 0)
continue;
bsize = blksize(fs, oip, i);
bsize = lfs_blksize(fs, oip, i);
if (oip->i_ffs1_db[i] > 0) {
/* Check for fragment size changes */
obsize = oip->i_lfs_fragsize[i];
real_released += btofsb(fs, obsize);
real_released += lfs_btofsb(fs, obsize);
oip->i_lfs_fragsize[i] = 0;
} else
obsize = 0;
blocksreleased += btofsb(fs, bsize);
blocksreleased += lfs_btofsb(fs, bsize);
oip->i_ffs1_db[i] = 0;
lfs_blkfree(fs, oip, bn, obsize, &lastseg, &bc);
lfs_deregister_block(ovp, bn);
@@ -520,22 +521,22 @@ lfs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred)
* Calculate amount of space we're giving
* back as old block size minus new block size.
*/
oldspace = blksize(fs, oip, lastblock);
oldspace = lfs_blksize(fs, oip, lastblock);
#if 0
olddspace = oip->i_lfs_fragsize[lastblock];
#endif
oip->i_size = oip->i_ffs1_size = length;
newspace = blksize(fs, oip, lastblock);
newspace = lfs_blksize(fs, oip, lastblock);
if (newspace == 0)
panic("itrunc: newspace");
if (oldspace - newspace > 0) {
blocksreleased += btofsb(fs, oldspace - newspace);
blocksreleased += lfs_btofsb(fs, oldspace - newspace);
}
#if 0
if (bn > 0 && olddspace - newspace > 0) {
/* No segment accounting here, just vnode */
real_released += btofsb(fs, olddspace - newspace);
real_released += lfs_btofsb(fs, olddspace - newspace);
}
#endif
}
@@ -545,11 +546,11 @@ done:
lfs_update_seguse(fs, oip, lastseg, bc);
#ifdef DIAGNOSTIC
for (level = SINGLE; level <= TRIPLE; level++)
if ((newblks[NDADDR + level] == 0) !=
if ((newblks[ULFS_NDADDR + level] == 0) !=
((oip->i_ffs1_ib[level]) == 0)) {
panic("lfs itrunc1");
}
for (i = 0; i < NDADDR; i++)
for (i = 0; i < ULFS_NDADDR; i++)
if ((newblks[i] == 0) != (oip->i_ffs1_db[i] == 0)) {
panic("lfs itrunc2");
}
@@ -586,14 +587,14 @@ done:
mutex_exit(&lfs_lock);
oip->i_flag |= IN_CHANGE;
#ifdef QUOTA
(void) chkdq(oip, -blocksreleased, NOCRED, 0);
#if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
(void) lfs_chkdq(oip, -blocksreleased, NOCRED, 0);
#endif
lfs_reserve(fs, ovp, NULL,
-btofsb(fs, (2 * NIADDR + 3) << fs->lfs_bshift));
-lfs_btofsb(fs, (2 * ULFS_NIADDR + 3) << fs->lfs_bshift));
genfs_node_unlock(ovp);
errout:
oip->i_lfs_hiblk = lblkno(fs, oip->i_size + fs->lfs_bsize - 1) - 1;
oip->i_lfs_hiblk = lfs_lblkno(fs, oip->i_size + fs->lfs_bsize - 1) - 1;
if (ovp != fs->lfs_ivnode)
lfs_segunlock(fs);
return (allerror ? allerror : error);
@@ -608,9 +609,9 @@ lfs_blkfree(struct lfs *fs, struct inode *ip, daddr_t daddr,
int error = 0;
ASSERT_SEGLOCK(fs);
bsize = fragroundup(fs, bsize);
bsize = lfs_fragroundup(fs, bsize);
if (daddr > 0) {
if (*lastseg != (seg = dtosn(fs, daddr))) {
if (*lastseg != (seg = lfs_dtosn(fs, daddr))) {
error = lfs_update_seguse(fs, ip, *lastseg, *num);
*num = bsize;
*lastseg = seg;
@@ -626,13 +627,11 @@ static int
lfs_update_seguse(struct lfs *fs, struct inode *ip, long lastseg, size_t num)
{
struct segdelta *sd;
struct vnode *vp;
ASSERT_SEGLOCK(fs);
if (lastseg < 0 || num == 0)
return 0;
vp = ITOV(ip);
LIST_FOREACH(sd, &ip->i_lfs_segdhd, list)
if (sd->segnum == lastseg)
break;
@@ -720,11 +719,11 @@ lfs_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn,
*/
factor = 1;
for (i = SINGLE; i < level; i++)
factor *= NINDIR(fs);
factor *= LFS_NINDIR(fs);
last = lastbn;
if (lastbn > 0)
last /= factor;
nblocks = btofsb(fs, fs->lfs_bsize);
nblocks = lfs_btofsb(fs, fs->lfs_bsize);
/*
* Get buffer of block pointers, zero those entries corresponding
* to blocks to be free'd, and update on disk copy first. Since
@@ -744,7 +743,7 @@ lfs_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn,
bp->b_flags |= B_READ;
if (bp->b_bcount > bp->b_bufsize)
panic("lfs_indirtrunc: bad buffer size");
bp->b_blkno = fsbtodb(fs, dbn);
bp->b_blkno = LFS_FSBTODB(fs, dbn);
VOP_STRATEGY(vp, bp);
error = biowait(bp);
}
@@ -760,7 +759,7 @@ lfs_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn,
memcpy((void *)copy, (void *)bap, (u_int)fs->lfs_bsize);
memset((void *)&bap[last + 1], 0,
/* XXX ondisk32 */
(u_int)(NINDIR(fs) - (last + 1)) * sizeof (int32_t));
(u_int)(LFS_NINDIR(fs) - (last + 1)) * sizeof (int32_t));
error = VOP_BWRITE(bp->b_vp, bp);
if (error)
allerror = error;
@@ -770,7 +769,7 @@ lfs_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn,
/*
* Recursively free totally unused blocks.
*/
for (i = NINDIR(fs) - 1, nlbn = lbn + 1 - i * factor; i > last;
for (i = LFS_NINDIR(fs) - 1, nlbn = lbn + 1 - i * factor; i > last;
i--, nlbn += factor) {
nb = bap[i];
if (nb == 0)
@@ -814,7 +813,7 @@ lfs_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn,
mutex_enter(&bufcache_lock);
if (bp->b_oflags & BO_DELWRI) {
LFS_UNLOCK_BUF(bp);
fs->lfs_avail += btofsb(fs, bp->b_bcount);
fs->lfs_avail += lfs_btofsb(fs, bp->b_bcount);
wakeup(&fs->lfs_avail);
}
brelsel(bp, BC_INVAL);
@@ -866,7 +865,7 @@ restart:
mutex_enter(bp->b_objlock);
if (bp->b_oflags & BO_DELWRI) {
bp->b_oflags &= ~BO_DELWRI;
fs->lfs_avail += btofsb(fs, bp->b_bcount);
fs->lfs_avail += lfs_btofsb(fs, bp->b_bcount);
wakeup(&fs->lfs_avail);
}
mutex_exit(bp->b_objlock);
@@ -888,7 +887,7 @@ restart:
mutex_enter(bp->b_objlock);
if (bp->b_oflags & BO_DELWRI) {
bp->b_oflags &= ~BO_DELWRI;
fs->lfs_avail += btofsb(fs, bp->b_bcount);
fs->lfs_avail += lfs_btofsb(fs, bp->b_bcount);
wakeup(&fs->lfs_avail);
}
mutex_exit(bp->b_objlock);
+335
View File
@@ -0,0 +1,335 @@
/* $NetBSD: lfs_inode.h,v 1.5 2013/06/18 08:01:00 dholland Exp $ */
/* from NetBSD: ulfs_inode.h,v 1.5 2013/06/06 00:51:50 dholland Exp */
/* from NetBSD: inode.h,v 1.64 2012/11/19 00:36:21 jakllsch Exp */
/*
* Copyright (c) 1982, 1989, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* 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.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* @(#)inode.h 8.9 (Berkeley) 5/14/95
*/
#ifndef _UFS_LFS_LFS_INODE_H_
#define _UFS_LFS_LFS_INODE_H_
/*
* Some of the userlevel code (fsck, newfs, lfs_cleanerd) wants to use
* the in-memory inode structure in a faked-up kernel environment.
* This header file provides a reasonably sanitized version of the
* structures and definitions needed for that purpose.
*/
#include <miscfs/genfs/genfs_node.h>
#include <ufs/lfs/lfs.h>
/*
* Adjustable filesystem parameters
*/
#define MIN_FREE_SEGS 20
#define MIN_RESV_SEGS 15
/*
* The following constants define the usage of the quota file array in the
* ulfsmount structure and dquot array in the inode structure. The semantics
* of the elements of these arrays are defined in the routine lfs_getinoquota;
* the remainder of the quota code treats them generically and need not be
* inspected when changing the size of the array.
*/
#define ULFS_MAXQUOTAS 2
#define ULFS_USRQUOTA 0 /* element used for user quotas */
#define ULFS_GRPQUOTA 1 /* element used for group quotas */
/*
* Lookup result state (other than the result inode). This is
* currently stashed in the vnode between VOP_LOOKUP and directory
* operation VOPs, which is gross.
*
* XXX ulr_diroff is a lookup hint from the previos call of VOP_LOOKUP.
* probably it should not be here.
*/
struct ulfs_lookup_results {
int32_t ulr_count; /* Size of free slot in directory. */
doff_t ulr_endoff; /* End of useful stuff in directory. */
doff_t ulr_diroff; /* Offset in dir, where we found last entry. */
doff_t ulr_offset; /* Offset of free space in directory. */
u_int32_t ulr_reclen; /* Size of found directory entry. */
};
/* notyet XXX */
#define ULFS_CHECK_CRAPCOUNTER(dp) ((void)(dp)->i_crapcounter)
/*
* Per-filesystem inode extensions.
*/
struct lfs_inode_ext;
/*
* The inode is used to describe each active (or recently active) file in the
* ULFS filesystem. It is composed of two types of information. The first part
* is the information that is needed only while the file is active (such as
* the identity of the file and linkage to speed its lookup). The second part
* is the permanent meta-data associated with the file which is read in
* from the permanent dinode from long term storage when the file becomes
* active, and is put back when the file is no longer being used.
*/
struct inode {
struct genfs_node i_gnode;
LIST_ENTRY(inode) i_hash;/* Hash chain. */
TAILQ_ENTRY(inode) i_nextsnap; /* snapshot file list. */
struct vnode *i_vnode; /* Vnode associated with this inode. */
struct ulfsmount *i_ump; /* Mount point associated with this inode. */
struct vnode *i_devvp; /* Vnode for block I/O. */
u_int32_t i_flag; /* flags, see below */
dev_t i_dev; /* Device associated with the inode. */
ino_t i_number; /* The identity of the inode. */
struct lfs *i_lfs; /* The LFS volume we belong to. */
void *i_unused1; /* Unused. */
struct dquot *i_dquot[ULFS_MAXQUOTAS]; /* Dquot structures. */
u_quad_t i_modrev; /* Revision level for NFS lease. */
struct lockf *i_lockf;/* Head of byte-level lock list. */
/*
* Side effects; used during (and after) directory lookup.
* XXX should not be here.
*/
struct ulfs_lookup_results i_crap;
unsigned i_crapcounter; /* serial number for i_crap */
/*
* Inode extensions
*/
union {
/* Other extensions could go here... */
struct lfs_inode_ext *lfs;
} inode_ext;
/*
* Copies from the on-disk dinode itself.
*
* These fields are currently only used by LFS.
*/
u_int16_t i_mode; /* IFMT, permissions; see below. */
int16_t i_nlink; /* File link count. */
u_int64_t i_size; /* File byte count. */
u_int32_t i_flags; /* Status flags (chflags). */
int32_t i_gen; /* Generation number. */
u_int32_t i_uid; /* File owner. */
u_int32_t i_gid; /* File group. */
u_int16_t i_omode; /* Old mode, for ulfs_reclaim. */
struct dirhash *i_dirhash; /* Hashing for large directories */
/*
* The on-disk dinode itself.
*/
union {
struct ulfs1_dinode *ffs1_din; /* 128 bytes of the on-disk dinode. */
struct ulfs2_dinode *ffs2_din;
} i_din;
};
#define i_ffs1_atime i_din.ffs1_din->di_atime
#define i_ffs1_atimensec i_din.ffs1_din->di_atimensec
#define i_ffs1_blocks i_din.ffs1_din->di_blocks
#define i_ffs1_ctime i_din.ffs1_din->di_ctime
#define i_ffs1_ctimensec i_din.ffs1_din->di_ctimensec
#define i_ffs1_db i_din.ffs1_din->di_db
#define i_ffs1_flags i_din.ffs1_din->di_flags
#define i_ffs1_gen i_din.ffs1_din->di_gen
#define i_ffs1_gid i_din.ffs1_din->di_gid
#define i_ffs1_ib i_din.ffs1_din->di_ib
#define i_ffs1_mode i_din.ffs1_din->di_mode
#define i_ffs1_mtime i_din.ffs1_din->di_mtime
#define i_ffs1_mtimensec i_din.ffs1_din->di_mtimensec
#define i_ffs1_nlink i_din.ffs1_din->di_nlink
#define i_ffs1_rdev i_din.ffs1_din->di_rdev
#define i_ffs1_size i_din.ffs1_din->di_size
#define i_ffs1_uid i_din.ffs1_din->di_uid
#define i_ffs2_atime i_din.ffs2_din->di_atime
#define i_ffs2_atimensec i_din.ffs2_din->di_atimensec
#define i_ffs2_birthtime i_din.ffs2_din->di_birthtime
#define i_ffs2_birthnsec i_din.ffs2_din->di_birthnsec
#define i_ffs2_blocks i_din.ffs2_din->di_blocks
#define i_ffs2_blksize i_din.ffs2_din->di_blksize
#define i_ffs2_ctime i_din.ffs2_din->di_ctime
#define i_ffs2_ctimensec i_din.ffs2_din->di_ctimensec
#define i_ffs2_db i_din.ffs2_din->di_db
#define i_ffs2_flags i_din.ffs2_din->di_flags
#define i_ffs2_gen i_din.ffs2_din->di_gen
#define i_ffs2_gid i_din.ffs2_din->di_gid
#define i_ffs2_ib i_din.ffs2_din->di_ib
#define i_ffs2_mode i_din.ffs2_din->di_mode
#define i_ffs2_mtime i_din.ffs2_din->di_mtime
#define i_ffs2_mtimensec i_din.ffs2_din->di_mtimensec
#define i_ffs2_nlink i_din.ffs2_din->di_nlink
#define i_ffs2_rdev i_din.ffs2_din->di_rdev
#define i_ffs2_size i_din.ffs2_din->di_size
#define i_ffs2_uid i_din.ffs2_din->di_uid
#define i_ffs2_kernflags i_din.ffs2_din->di_kernflags
#define i_ffs2_extsize i_din.ffs2_din->di_extsize
#define i_ffs2_extb i_din.ffs2_din->di_extb
/* These flags are kept in i_flag. */
#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_UNUSED 0x0020 */ /* unused, was IN_RENAME */
#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 */
#define IN_CDIROP 0x4000 /* LFS: dirop completed pending i/o */
/*
* LFS inode extensions.
*/
struct lfs_inode_ext {
off_t lfs_osize; /* size of file on disk */
u_int32_t lfs_effnblocks; /* number of blocks when i/o completes */
size_t lfs_fragsize[ULFS_NDADDR]; /* size of on-disk direct blocks */
TAILQ_ENTRY(inode) lfs_dchain; /* Dirop chain. */
TAILQ_ENTRY(inode) lfs_pchain; /* Paging chain. */
#define LFSI_NO_GOP_WRITE 0x01
#define LFSI_DELETED 0x02
#define LFSI_WRAPBLOCK 0x04
#define LFSI_WRAPWAIT 0x08
#define LFSI_BMAP 0x10
u_int32_t lfs_iflags; /* Inode flags */
daddr_t lfs_hiblk; /* Highest lbn held by inode */
#ifdef _KERNEL
SPLAY_HEAD(lfs_splay, lbnentry) lfs_lbtree; /* Tree of balloc'd lbns */
int lfs_nbtree; /* Size of tree */
LIST_HEAD(, segdelta) lfs_segdhd;
#endif
int16_t lfs_odnlink; /* on-disk nlink count for cleaner */
};
#define i_lfs_osize inode_ext.lfs->lfs_osize
#define i_lfs_effnblks inode_ext.lfs->lfs_effnblocks
#define i_lfs_fragsize inode_ext.lfs->lfs_fragsize
#define i_lfs_dchain inode_ext.lfs->lfs_dchain
#define i_lfs_pchain inode_ext.lfs->lfs_pchain
#define i_lfs_iflags inode_ext.lfs->lfs_iflags
#define i_lfs_hiblk inode_ext.lfs->lfs_hiblk
#define i_lfs_lbtree inode_ext.lfs->lfs_lbtree
#define i_lfs_nbtree inode_ext.lfs->lfs_nbtree
#define i_lfs_segdhd inode_ext.lfs->lfs_segdhd
#define i_lfs_odnlink inode_ext.lfs->lfs_odnlink
/*
* "struct buf" associated definitions
*/
#ifdef _KERNEL
# define LFS_IS_MALLOC_BUF(bp) ((bp)->b_iodone == lfs_callback)
# ifdef DEBUG
# define LFS_DEBUG_COUNTLOCKED(m) do { \
if (lfs_debug_log_subsys[DLOG_LLIST]) { \
lfs_countlocked(&locked_queue_count, &locked_queue_bytes, (m)); \
cv_broadcast(&locked_queue_cv); \
} \
} while (0)
# else
# define LFS_DEBUG_COUNTLOCKED(m)
# endif
/* log for debugging writes to the Ifile */
# ifdef DEBUG
struct lfs_log_entry {
const char *op;
const char *file;
int pid;
int line;
daddr_t block;
unsigned long flags;
};
extern int lfs_lognum;
extern struct lfs_log_entry lfs_log[LFS_LOGLENGTH];
# define LFS_BWRITE_LOG(bp) lfs_bwrite_log((bp), __FILE__, __LINE__)
# define LFS_ENTER_LOG(theop, thefile, theline, lbn, theflags, thepid) do {\
int _s; \
\
mutex_enter(&lfs_lock); \
_s = splbio(); \
lfs_log[lfs_lognum].op = theop; \
lfs_log[lfs_lognum].file = thefile; \
lfs_log[lfs_lognum].line = (theline); \
lfs_log[lfs_lognum].pid = (thepid); \
lfs_log[lfs_lognum].block = (lbn); \
lfs_log[lfs_lognum].flags = (theflags); \
lfs_lognum = (lfs_lognum + 1) % LFS_LOGLENGTH; \
splx(_s); \
mutex_exit(&lfs_lock); \
} while (0)
# define LFS_BCLEAN_LOG(fs, bp) do { \
if ((bp)->b_vp == (fs)->lfs_ivnode) \
LFS_ENTER_LOG("clear", __FILE__, __LINE__, \
bp->b_lblkno, bp->b_flags, curproc->p_pid);\
} while (0)
/* Must match list in lfs_vfsops.c ! */
# define DLOG_RF 0 /* roll forward */
# define DLOG_ALLOC 1 /* inode alloc */
# define DLOG_AVAIL 2 /* lfs_{,r,f}avail */
# define DLOG_FLUSH 3 /* flush */
# define DLOG_LLIST 4 /* locked list accounting */
# define DLOG_WVNODE 5 /* vflush/writevnodes verbose */
# define DLOG_VNODE 6 /* vflush/writevnodes */
# define DLOG_SEG 7 /* segwrite */
# define DLOG_SU 8 /* seguse accounting */
# define DLOG_CLEAN 9 /* cleaner routines */
# define DLOG_MOUNT 10 /* mount/unmount */
# define DLOG_PAGE 11 /* putpages/gop_write */
# define DLOG_DIROP 12 /* dirop accounting */
# define DLOG_MALLOC 13 /* lfs_malloc accounting */
# define DLOG_MAX 14 /* The terminator */
# define DLOG(a) lfs_debug_log a
# else /* ! DEBUG */
# define LFS_BCLEAN_LOG(fs, bp)
# define LFS_BWRITE_LOG(bp) VOP_BWRITE((bp)->b_vp, (bp))
# define DLOG(a)
# endif /* ! DEBUG */
#else /* ! _KERNEL */
# define LFS_BWRITE_LOG(bp) VOP_BWRITE((bp))
#endif /* _KERNEL */
#endif /* _UFS_LFS_LFS_INODE_H_ */
+4 -4
View File
@@ -1,4 +1,4 @@
/* $NetBSD: lfs_itimes.c,v 1.12 2008/04/28 20:24:11 martin Exp $ */
/* $NetBSD: lfs_itimes.c,v 1.15 2013/06/08 02:16:03 dholland Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -29,15 +29,13 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_itimes.c,v 1.12 2008/04/28 20:24:11 martin Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_itimes.c,v 1.15 2013/06/08 02:16:03 dholland Exp $");
#include <sys/param.h>
#include <sys/time.h>
#include <sys/mount.h>
#include <sys/buf.h>
#include <ufs/ufs/inode.h>
#ifndef _KERNEL
#include "bufcache.h"
#include "vnode.h"
@@ -46,11 +44,13 @@ __KERNEL_RCSID(0, "$NetBSD: lfs_itimes.c,v 1.12 2008/04/28 20:24:11 martin Exp $
#define buf ubuf
#define panic call_panic
#else
#include <ufs/lfs/ulfs_inode.h>
#include <ufs/lfs/lfs_extern.h>
#include <sys/kauth.h>
#endif
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_inode.h>
void
lfs_itimes(struct inode *ip, const struct timespec *acc,
+113
View File
@@ -0,0 +1,113 @@
/* $NetBSD: lfs_kernel.h,v 1.1 2013/07/28 01:05:52 dholland Exp $ */
/* from NetBSD: lfs.h,v 1.157 2013/06/28 16:14:06 matt Exp */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Konrad E. Schroder <perseant@hhhh.org>.
*
* 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``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 FOUNDATION OR CONTRIBUTORS
* 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.
*/
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* @(#)lfs.h 8.9 (Berkeley) 5/8/95
*/
#ifndef _UFS_LFS_LFS_KERNEL_H_
#define _UFS_LFS_LFS_KERNEL_H_
#include <ufs/lfs/lfs.h>
extern struct lfs_stats lfs_stats;
/* XXX MP */
#define LFS_SEGLOCK_HELD(fs) \
((fs)->lfs_seglock != 0 && \
(fs)->lfs_lockpid == curproc->p_pid && \
(fs)->lfs_locklwp == curlwp->l_lid)
struct lfs_cluster {
size_t bufsize; /* Size of kept data */
struct buf **bpp; /* Array of kept buffers */
int bufcount; /* Number of kept buffers */
#define LFS_CL_MALLOC 0x00000001
#define LFS_CL_SHIFT 0x00000002
#define LFS_CL_SYNC 0x00000004
u_int32_t flags; /* Flags */
struct lfs *fs; /* LFS that this belongs to */
struct segment *seg; /* Segment structure, for LFS_CL_SYNC */
};
/*
* Splay tree containing block numbers allocated through lfs_balloc.
*/
struct lbnentry {
SPLAY_ENTRY(lbnentry) entry;
daddr_t lbn;
};
/*
* Compat fcntls. Defined for kernel only. Userland always uses
* "the one true version".
*/
#include <compat/sys/time_types.h>
#define LFCNSEGWAITALL_COMPAT _FCNW_FSPRIV('L', 0, struct timeval50)
#define LFCNSEGWAIT_COMPAT _FCNW_FSPRIV('L', 1, struct timeval50)
#define LFCNIFILEFH_COMPAT _FCNW_FSPRIV('L', 5, struct lfs_fhandle)
#define LFCNIFILEFH_COMPAT2 _FCN_FSPRIV(F_FSOUT, 'L', 11, 32)
#define LFCNWRAPSTOP_COMPAT _FCNO_FSPRIV('L', 9)
#define LFCNWRAPGO_COMPAT _FCNO_FSPRIV('L', 10)
#define LFCNSEGWAITALL_COMPAT_50 _FCNR_FSPRIV('L', 0, struct timeval50)
#define LFCNSEGWAIT_COMPAT_50 _FCNR_FSPRIV('L', 1, struct timeval50)
#endif /* _UFS_LFS_LFS_KERNEL_H_ */
File diff suppressed because it is too large Load Diff
+53 -52
View File
@@ -1,4 +1,4 @@
/* $NetBSD: lfs_rfw.c,v 1.12 2009/02/22 20:28:07 ad Exp $ */
/* $NetBSD: lfs_rfw.c,v 1.18 2013/07/28 01:05:52 dholland Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_rfw.c,v 1.12 2009/02/22 20:28:07 ad Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_rfw.c,v 1.18 2013/07/28 01:05:52 dholland Exp $");
#if defined(_KERNEL_OPT)
#include "opt_quota.h"
@@ -62,10 +62,10 @@ __KERNEL_RCSID(0, "$NetBSD: lfs_rfw.c,v 1.12 2009/02/22 20:28:07 ad Exp $");
#include <miscfs/specfs/specdev.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/ufs_extern.h>
#include <ufs/lfs/ulfs_quotacommon.h>
#include <ufs/lfs/ulfs_inode.h>
#include <ufs/lfs/ulfsmount.h>
#include <ufs/lfs/ulfs_extern.h>
#include <uvm/uvm.h>
#include <uvm/uvm_stat.h>
@@ -73,6 +73,7 @@ __KERNEL_RCSID(0, "$NetBSD: lfs_rfw.c,v 1.12 2009/02/22 20:28:07 ad Exp $");
#include <uvm/uvm_pdaemon.h>
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_kernel.h>
#include <ufs/lfs/lfs_extern.h>
#include <miscfs/genfs/genfs.h>
@@ -180,9 +181,9 @@ lfs_rf_valloc(struct lfs *fs, ino_t ino, int vers, struct lwp *l,
* this later if it turns out to be some other kind of file.
*/
ip = VTOI(vp);
ip->i_mode = ip->i_ffs1_mode = IFREG;
ip->i_mode = ip->i_ffs1_mode = LFS_IFREG;
ip->i_nlink = ip->i_ffs1_nlink = 1;
ufs_vinit(vp->v_mount, lfs_specop_p, lfs_fifoop_p, &vp);
ulfs_vinit(vp->v_mount, lfs_specop_p, lfs_fifoop_p, &vp);
ip = VTOI(vp);
DLOG((DLOG_RF, "lfs_rf_valloc: ino %d vp %p\n", ino, vp));
@@ -216,7 +217,7 @@ update_meta(struct lfs *fs, ino_t ino, int vers, daddr_t lbn,
struct inode *ip;
#ifdef DEBUG
daddr_t odaddr;
struct indir a[NIADDR];
struct indir a[ULFS_NIADDR];
int num;
int i;
#endif /* DEBUG */
@@ -239,7 +240,7 @@ update_meta(struct lfs *fs, ino_t ino, int vers, daddr_t lbn,
/* No need to write, the block is already on disk */
if (bp->b_oflags & BO_DELWRI) {
LFS_UNLOCK_BUF(bp);
fs->lfs_avail += btofsb(fs, bp->b_bcount);
fs->lfs_avail += lfs_btofsb(fs, bp->b_bcount);
}
brelse(bp, BC_INVAL);
@@ -253,7 +254,7 @@ update_meta(struct lfs *fs, ino_t ino, int vers, daddr_t lbn,
if (ip->i_size <= (lbn << fs->lfs_bshift)) {
u_int64_t newsize;
if (lbn < NDADDR)
if (lbn < ULFS_NDADDR)
newsize = ip->i_ffs1_size = (lbn << fs->lfs_bshift) +
(size - fs->lfs_fsize) + 1;
else
@@ -271,23 +272,23 @@ update_meta(struct lfs *fs, ino_t ino, int vers, daddr_t lbn,
lfs_update_single(fs, NULL, vp, lbn, ndaddr, size);
LFS_SEGENTRY(sup, fs, dtosn(fs, ndaddr), bp);
LFS_SEGENTRY(sup, fs, lfs_dtosn(fs, ndaddr), bp);
sup->su_nbytes += size;
LFS_WRITESEGENTRY(sup, fs, dtosn(fs, ndaddr), bp);
LFS_WRITESEGENTRY(sup, fs, lfs_dtosn(fs, ndaddr), bp);
/* differences here should be due to UNWRITTEN indirect blocks. */
KASSERT((lblkno(fs, ip->i_size) > NDADDR &&
KASSERT((lfs_lblkno(fs, ip->i_size) > ULFS_NDADDR &&
ip->i_lfs_effnblks == ip->i_ffs1_blocks) ||
ip->i_lfs_effnblks >= ip->i_ffs1_blocks);
#ifdef DEBUG
/* Now look again to make sure it worked */
ufs_bmaparray(vp, lbn, &odaddr, &a[0], &num, NULL, NULL);
ulfs_bmaparray(vp, lbn, &odaddr, &a[0], &num, NULL, NULL);
for (i = num; i > 0; i--) {
if (!a[i].in_exists)
panic("update_meta: absent %d lv indirect block", i);
}
if (dbtofsb(fs, odaddr) != ndaddr)
if (LFS_DBTOFSB(fs, odaddr) != ndaddr)
DLOG((DLOG_RF, "update_meta: failed setting ino %d lbn %"
PRId64 " to %" PRId64 "\n", ino, lbn, ndaddr));
#endif /* DEBUG */
@@ -301,7 +302,7 @@ update_inoblk(struct lfs *fs, daddr_t offset, kauth_cred_t cred,
{
struct vnode *devvp, *vp;
struct inode *ip;
struct ufs1_dinode *dip;
struct ulfs1_dinode *dip;
struct buf *dbp, *ibp;
int error;
daddr_t daddr;
@@ -314,14 +315,14 @@ update_inoblk(struct lfs *fs, daddr_t offset, kauth_cred_t cred,
* Get the inode, update times and perms.
* DO NOT update disk blocks, we do that separately.
*/
error = bread(devvp, fsbtodb(fs, offset), fs->lfs_ibsize,
error = bread(devvp, LFS_FSBTODB(fs, offset), fs->lfs_ibsize,
cred, 0, &dbp);
if (error) {
DLOG((DLOG_RF, "update_inoblk: bread returned %d\n", error));
return error;
}
dip = ((struct ufs1_dinode *)(dbp->b_data)) + INOPB(fs);
while (--dip >= (struct ufs1_dinode *)dbp->b_data) {
dip = ((struct ulfs1_dinode *)(dbp->b_data)) + LFS_INOPB(fs);
while (--dip >= (struct ulfs1_dinode *)dbp->b_data) {
if (dip->di_inumber > LFS_IFILE_INUM) {
error = lfs_rf_valloc(fs, dip->di_inumber, dip->di_gen,
l, &vp);
@@ -335,7 +336,7 @@ update_inoblk(struct lfs *fs, daddr_t offset, kauth_cred_t cred,
lfs_truncate(vp, dip->di_size, 0, NOCRED);
/* Get mode, link count, size, and times */
memcpy(ip->i_din.ffs1_din, dip,
offsetof(struct ufs1_dinode, di_db[0]));
offsetof(struct ulfs1_dinode, di_db[0]));
/* Then the rest, except di_blocks */
ip->i_flags = ip->i_ffs1_flags = dip->di_flags;
@@ -350,30 +351,30 @@ update_inoblk(struct lfs *fs, daddr_t offset, kauth_cred_t cred,
LFS_SET_UINO(ip, IN_CHANGE | IN_UPDATE);
/* Re-initialize to get type right */
ufs_vinit(vp->v_mount, lfs_specop_p, lfs_fifoop_p,
ulfs_vinit(vp->v_mount, lfs_specop_p, lfs_fifoop_p,
&vp);
vput(vp);
/* Record change in location */
LFS_IENTRY(ifp, fs, dip->di_inumber, ibp);
daddr = ifp->if_daddr;
ifp->if_daddr = dbtofsb(fs, dbp->b_blkno);
ifp->if_daddr = LFS_DBTOFSB(fs, dbp->b_blkno);
error = LFS_BWRITE_LOG(ibp); /* Ifile */
/* And do segment accounting */
if (dtosn(fs, daddr) != dtosn(fs, dbtofsb(fs, dbp->b_blkno))) {
if (lfs_dtosn(fs, daddr) != lfs_dtosn(fs, LFS_DBTOFSB(fs, dbp->b_blkno))) {
if (daddr > 0) {
LFS_SEGENTRY(sup, fs, dtosn(fs, daddr),
LFS_SEGENTRY(sup, fs, lfs_dtosn(fs, daddr),
ibp);
sup->su_nbytes -= sizeof (struct ufs1_dinode);
sup->su_nbytes -= sizeof (struct ulfs1_dinode);
LFS_WRITESEGENTRY(sup, fs,
dtosn(fs, daddr),
lfs_dtosn(fs, daddr),
ibp);
}
LFS_SEGENTRY(sup, fs, dtosn(fs, dbtofsb(fs, dbp->b_blkno)),
LFS_SEGENTRY(sup, fs, lfs_dtosn(fs, LFS_DBTOFSB(fs, dbp->b_blkno)),
ibp);
sup->su_nbytes += sizeof (struct ufs1_dinode);
sup->su_nbytes += sizeof (struct ulfs1_dinode);
LFS_WRITESEGENTRY(sup, fs,
dtosn(fs, dbtofsb(fs, dbp->b_blkno)),
lfs_dtosn(fs, LFS_DBTOFSB(fs, dbp->b_blkno)),
ibp);
}
}
@@ -406,15 +407,15 @@ check_segsum(struct lfs *fs, daddr_t offset, u_int64_t nextserial,
* If the segment has a superblock and we're at the top
* of the segment, skip the superblock.
*/
if (sntod(fs, dtosn(fs, offset)) == offset) {
LFS_SEGENTRY(sup, fs, dtosn(fs, offset), bp);
if (lfs_sntod(fs, lfs_dtosn(fs, offset)) == offset) {
LFS_SEGENTRY(sup, fs, lfs_dtosn(fs, offset), bp);
if (sup->su_flags & SEGUSE_SUPERBLOCK)
offset += btofsb(fs, LFS_SBPAD);
offset += lfs_btofsb(fs, LFS_SBPAD);
brelse(bp, 0);
}
/* Read in the segment summary */
error = bread(devvp, fsbtodb(fs, offset), fs->lfs_sumsize,
error = bread(devvp, LFS_FSBTODB(fs, offset), fs->lfs_sumsize,
cred, 0, &bp);
if (error)
return -1;
@@ -457,9 +458,9 @@ check_segsum(struct lfs *fs, daddr_t offset, u_int64_t nextserial,
if (pseg_flags)
*pseg_flags = ssp->ss_flags;
oldoffset = offset;
offset += btofsb(fs, fs->lfs_sumsize);
offset += lfs_btofsb(fs, fs->lfs_sumsize);
ninos = howmany(ssp->ss_ninos, INOPB(fs));
ninos = howmany(ssp->ss_ninos, LFS_INOPB(fs));
/* XXX ondisk32 */
iaddr = (int32_t *)((char*)bp->b_data + fs->lfs_sumsize - sizeof(int32_t));
if (flags & CHECK_CKSUM) {
@@ -487,7 +488,7 @@ check_segsum(struct lfs *fs, daddr_t offset, u_int64_t nextserial,
if (ninos && *iaddr == offset) {
if (flags & CHECK_CKSUM) {
/* Read in the head and add to the buffer */
error = bread(devvp, fsbtodb(fs, offset), fs->lfs_bsize,
error = bread(devvp, LFS_FSBTODB(fs, offset), fs->lfs_bsize,
cred, 0, &dbp);
if (error) {
offset = -1;
@@ -503,7 +504,7 @@ check_segsum(struct lfs *fs, daddr_t offset, u_int64_t nextserial,
goto err2;
}
}
offset += btofsb(fs, fs->lfs_ibsize);
offset += lfs_btofsb(fs, fs->lfs_ibsize);
--iaddr;
--ninos;
--i; /* compensate */
@@ -514,7 +515,7 @@ check_segsum(struct lfs *fs, daddr_t offset, u_int64_t nextserial,
if (j == fip->fi_nblocks - 1)
size = fip->fi_lastlength;
if (flags & CHECK_CKSUM) {
error = bread(devvp, fsbtodb(fs, offset), size,
error = bread(devvp, LFS_FSBTODB(fs, offset), size,
cred, 0, &dbp);
if (error) {
offset = -1;
@@ -530,7 +531,7 @@ check_segsum(struct lfs *fs, daddr_t offset, u_int64_t nextserial,
update_meta(fs, fip->fi_ino, fip->fi_version,
fip->fi_blocks[j], offset, size, l);
}
offset += btofsb(fs, size);
offset += lfs_btofsb(fs, size);
}
/* XXX ondisk32 */
fip = (FINFO *)(((char *)fip) + FINFOSIZE
@@ -549,15 +550,15 @@ check_segsum(struct lfs *fs, daddr_t offset, u_int64_t nextserial,
}
/* If we're at the end of the segment, move to the next */
if (dtosn(fs, offset + btofsb(fs, fs->lfs_sumsize + fs->lfs_bsize)) !=
dtosn(fs, offset)) {
if (dtosn(fs, offset) == dtosn(fs, ssp->ss_next)) {
if (lfs_dtosn(fs, offset + lfs_btofsb(fs, fs->lfs_sumsize + fs->lfs_bsize)) !=
lfs_dtosn(fs, offset)) {
if (lfs_dtosn(fs, offset) == lfs_dtosn(fs, ssp->ss_next)) {
offset = -1;
goto err2;
}
offset = ssp->ss_next;
DLOG((DLOG_RF, "LFS roll forward: moving to offset 0x%" PRIx64
" -> segment %d\n", offset, dtosn(fs,offset)));
" -> segment %d\n", offset, lfs_dtosn(fs,offset)));
}
if (flags & CHECK_UPDATE) {
@@ -621,22 +622,22 @@ lfs_roll_forward(struct lfs *fs, struct mount *mp, struct lwp *l)
flags = 0x0;
DLOG((DLOG_RF, "LFS roll forward phase 1: start at offset 0x%"
PRIx64 "\n", offset));
LFS_SEGENTRY(sup, fs, dtosn(fs, offset), bp);
LFS_SEGENTRY(sup, fs, lfs_dtosn(fs, offset), bp);
if (!(sup->su_flags & SEGUSE_DIRTY))
--fs->lfs_nclean;
sup->su_flags |= SEGUSE_DIRTY;
LFS_WRITESEGENTRY(sup, fs, dtosn(fs, offset), bp);
LFS_WRITESEGENTRY(sup, fs, lfs_dtosn(fs, offset), bp);
nextserial = fs->lfs_serial + 1;
while ((offset = check_segsum(fs, offset, nextserial,
cred, CHECK_CKSUM, &flags, l)) > 0) {
nextserial++;
if (sntod(fs, oldoffset) != sntod(fs, offset)) {
LFS_SEGENTRY(sup, fs, dtosn(fs, oldoffset),
if (lfs_sntod(fs, oldoffset) != lfs_sntod(fs, offset)) {
LFS_SEGENTRY(sup, fs, lfs_dtosn(fs, oldoffset),
bp);
if (!(sup->su_flags & SEGUSE_DIRTY))
--fs->lfs_nclean;
sup->su_flags |= SEGUSE_DIRTY;
LFS_WRITESEGENTRY(sup, fs, dtosn(fs, oldoffset),
LFS_WRITESEGENTRY(sup, fs, lfs_dtosn(fs, oldoffset),
bp);
}
@@ -665,8 +666,8 @@ lfs_roll_forward(struct lfs *fs, struct mount *mp, struct lwp *l)
/* Don't overwrite what we're trying to preserve */
offset = fs->lfs_offset;
fs->lfs_offset = lastgoodpseg;
fs->lfs_curseg = sntod(fs, dtosn(fs, fs->lfs_offset));
for (sn = curseg = dtosn(fs, fs->lfs_curseg);;) {
fs->lfs_curseg = lfs_sntod(fs, lfs_dtosn(fs, fs->lfs_offset));
for (sn = curseg = lfs_dtosn(fs, fs->lfs_curseg);;) {
sn = (sn + 1) % fs->lfs_nseg;
if (sn == curseg)
panic("lfs_mountfs: no clean segments");
@@ -676,7 +677,7 @@ lfs_roll_forward(struct lfs *fs, struct mount *mp, struct lwp *l)
if (!dirty)
break;
}
fs->lfs_nextseg = sntod(fs, sn);
fs->lfs_nextseg = lfs_sntod(fs, sn);
/*
* Phase II: Roll forward from the first superblock.
+166 -128
View File
@@ -1,4 +1,4 @@
/* $NetBSD: lfs_segment.c,v 1.222 2011/07/11 08:27:40 hannken Exp $ */
/* $NetBSD: lfs_segment.c,v 1.233 2013/10/29 09:53:51 hannken Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -60,7 +60,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_segment.c,v 1.222 2011/07/11 08:27:40 hannken Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_segment.c,v 1.233 2013/10/29 09:53:51 hannken Exp $");
#ifdef DEBUG
# define vndebug(vp, str) do { \
@@ -95,12 +95,12 @@ __KERNEL_RCSID(0, "$NetBSD: lfs_segment.c,v 1.222 2011/07/11 08:27:40 hannken Ex
#include <miscfs/specfs/specdev.h>
#include <miscfs/fifofs/fifo.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/dir.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/ufs_extern.h>
#include <ufs/lfs/ulfs_inode.h>
#include <ufs/lfs/ulfsmount.h>
#include <ufs/lfs/ulfs_extern.h>
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_kernel.h>
#include <ufs/lfs/lfs_extern.h>
#include <uvm/uvm.h>
@@ -195,13 +195,15 @@ lfs_vflush(struct vnode *vp)
int error;
int flushed;
int relock;
int loopcount;
ip = VTOI(vp);
fs = VFSTOUFS(vp->v_mount)->um_lfs;
fs = VFSTOULFS(vp->v_mount)->um_lfs;
relock = 0;
top:
KASSERT(mutex_owned(vp->v_interlock) == false);
KASSERT(mutex_owned(&lfs_lock) == false);
KASSERT(mutex_owned(&bufcache_lock) == false);
ASSERT_NO_SEGLOCK(fs);
if (ip->i_flag & IN_CLEANING) {
ivndebug(vp,"vflush/in_cleaning");
@@ -230,15 +232,15 @@ lfs_vflush(struct vnode *vp)
struct vm_page *pg;
voff_t off;
for (off = lblktosize(fs, bp->b_lblkno);
off < lblktosize(fs, bp->b_lblkno + 1);
for (off = lfs_lblktosize(fs, bp->b_lblkno);
off < lfs_lblktosize(fs, bp->b_lblkno + 1);
off += PAGE_SIZE) {
pg = uvm_pagelookup(&vp->v_uobj, off);
if (pg == NULL)
continue;
if ((pg->flags & PG_CLEAN) == 0 ||
pmap_is_modified(pg)) {
fs->lfs_avail += btofsb(fs,
fs->lfs_avail += lfs_btofsb(fs,
bp->b_bcount);
wakeup(&fs->lfs_avail);
mutex_exit(vp->v_interlock);
@@ -257,7 +259,7 @@ lfs_vflush(struct vnode *vp)
&& tbp->b_lblkno == bp->b_lblkno
&& tbp != bp)
{
fs->lfs_avail += btofsb(fs,
fs->lfs_avail += lfs_btofsb(fs,
bp->b_bcount);
wakeup(&fs->lfs_avail);
mutex_exit(vp->v_interlock);
@@ -280,7 +282,10 @@ lfs_vflush(struct vnode *vp)
mutex_exit(vp->v_interlock);
/* Protect against VI_XLOCK deadlock in vinvalbuf() */
lfs_seglock(fs, SEGM_SYNC);
lfs_seglock(fs, SEGM_SYNC | ((vp->v_iflag & VI_XLOCK) ? SEGM_RECLAIM : 0));
if (vp->v_iflag & VI_XLOCK) {
fs->lfs_reclino = ip->i_number;
}
/* If we're supposed to flush a freed inode, just toss it */
if (ip->i_lfs_iflags & LFSI_DELETED) {
@@ -300,7 +305,7 @@ lfs_vflush(struct vnode *vp)
KASSERT((bp->b_flags & B_GATHERED) == 0);
if (bp->b_oflags & BO_DELWRI) { /* XXX always true? */
fs->lfs_avail += btofsb(fs, bp->b_bcount);
fs->lfs_avail += lfs_btofsb(fs, bp->b_bcount);
wakeup(&fs->lfs_avail);
}
/* Copied from lfs_writeseg */
@@ -376,15 +381,18 @@ lfs_vflush(struct vnode *vp)
#endif
do {
loopcount = 0;
#ifdef DEBUG
int loopcount = 0;
#endif
do {
if (LIST_FIRST(&vp->v_dirtyblkhd) != NULL) {
relock = lfs_writefile(fs, sp, vp);
if (relock) {
if (relock && vp != fs->lfs_ivnode) {
/*
* Might have to wait for the
* cleaner to run; but we're
* still not done with this vnode.
* XXX we can do better than this.
*/
KDASSERT(ip->i_number != LFS_IFILE_INUM);
lfs_writeinode(fs, sp, ip);
@@ -486,9 +494,16 @@ lfs_writevnodes(struct lfs *fs, struct mount *mp, struct segment *sp, int op)
* After this, pages might be busy
* due to our own previous putpages.
* Start actual segment write here to avoid deadlock.
* If we were just writing one segment and we've done
* that, break out.
*/
mutex_exit(&mntvnode_lock);
(void)lfs_writeseg(fs, sp);
if (lfs_writeseg(fs, sp) &&
(sp->seg_flags & SEGM_SINGLE) &&
fs->lfs_curseg != fs->lfs_startseg) {
DLOG((DLOG_VNODE, "lfs_writevnodes: breaking out of segment write at daddr 0x%x\n", fs->lfs_offset));
break;
}
goto loop;
}
@@ -609,9 +624,8 @@ lfs_segwrite(struct mount *mp, int flags)
int dirty;
int redo;
int um_error;
int loopcount;
fs = VFSTOUFS(mp)->um_lfs;
fs = VFSTOULFS(mp)->um_lfs;
ASSERT_MAYBE_SEGLOCK(fs);
if (fs->lfs_ronly)
@@ -626,6 +640,10 @@ lfs_segwrite(struct mount *mp, int flags)
*/
do_ckp = LFS_SHOULD_CHECKPOINT(fs, flags);
/* We can't do a partial write and checkpoint at the same time. */
if (do_ckp)
flags &= ~SEGM_SINGLE;
lfs_seglock(fs, flags | (do_ckp ? SEGM_CKP : 0));
sp = fs->lfs_sp;
if (sp->seg_flags & (SEGM_CLEAN | SEGM_CKP))
@@ -645,6 +663,11 @@ lfs_segwrite(struct mount *mp, int flags)
else if (!(sp->seg_flags & SEGM_FORCE_CKP)) {
do {
um_error = lfs_writevnodes(fs, mp, sp, VN_REG);
if ((sp->seg_flags & SEGM_SINGLE) &&
fs->lfs_curseg != fs->lfs_startseg) {
DLOG((DLOG_SEG, "lfs_segwrite: breaking out of segment write at daddr 0x%x\n", fs->lfs_offset));
break;
}
if (do_ckp || fs->lfs_dirops == 0) {
if (!writer_set) {
@@ -682,7 +705,7 @@ lfs_segwrite(struct mount *mp, int flags)
maxseg = min(segleft, fs->lfs_sepb);
for (i = 0; i < maxseg; i++) {
sn = curseg + i;
if (sn != dtosn(fs, fs->lfs_curseg) &&
if (sn != lfs_dtosn(fs, fs->lfs_curseg) &&
segusep->su_flags & SEGUSE_ACTIVE) {
segusep->su_flags &= ~SEGUSE_ACTIVE;
--fs->lfs_nactive;
@@ -711,8 +734,9 @@ lfs_segwrite(struct mount *mp, int flags)
did_ckp = 0;
if (do_ckp || fs->lfs_doifile) {
vp = fs->lfs_ivnode;
vn_lock(vp, LK_EXCLUSIVE);
loopcount = 0;
#ifdef DEBUG
int loopcount = 0;
#endif
do {
#ifdef DEBUG
LFS_ENTER_LOG("pretend", __FILE__, __LINE__, 0, 0, curproc->p_pid);
@@ -784,7 +808,6 @@ lfs_segwrite(struct mount *mp, int flags)
}
#endif
mutex_exit(vp->v_interlock);
VOP_UNLOCK(vp);
} else {
(void) lfs_writeseg(fs, sp);
}
@@ -823,7 +846,6 @@ lfs_segwrite(struct mount *mp, int flags)
int
lfs_writefile(struct lfs *fs, struct segment *sp, struct vnode *vp)
{
struct finfo *fip;
struct inode *ip;
int i, frag;
int error;
@@ -832,7 +854,6 @@ lfs_writefile(struct lfs *fs, struct segment *sp, struct vnode *vp)
error = 0;
ip = VTOI(vp);
fip = sp->fip;
lfs_acquire_finfo(fs, ip->i_number, ip->i_gen);
if (vp->v_uflag & VU_DIROP)
@@ -887,7 +908,7 @@ lfs_writefile(struct lfs *fs, struct segment *sp, struct vnode *vp)
*/
frag = 0;
if (sp->seg_flags & SEGM_CLEAN) {
for (i = 0; i < NDADDR; i++)
for (i = 0; i < ULFS_NDADDR; i++)
if (ip->i_lfs_fragsize[i] > 0 &&
ip->i_lfs_fragsize[i] < fs->lfs_bsize)
++frag;
@@ -902,7 +923,6 @@ lfs_writefile(struct lfs *fs, struct segment *sp, struct vnode *vp)
lfs_gather(fs, sp, vp, lfs_match_dindir);
lfs_gather(fs, sp, vp, lfs_match_tindir);
}
fip = sp->fip;
lfs_release_finfo(fs);
return error;
@@ -919,7 +939,7 @@ lfs_update_iaddr(struct lfs *fs, struct segment *sp, struct inode *ip, daddr_t n
IFILE *ifp;
SEGUSE *sup;
ino_t ino;
int redo_ifile, error;
int redo_ifile;
u_int32_t sn;
redo_ifile = 0;
@@ -931,12 +951,12 @@ lfs_update_iaddr(struct lfs *fs, struct segment *sp, struct inode *ip, daddr_t n
ino = ip->i_number;
if (ino == LFS_IFILE_INUM) {
daddr = fs->lfs_idaddr;
fs->lfs_idaddr = dbtofsb(fs, ndaddr);
fs->lfs_idaddr = LFS_DBTOFSB(fs, ndaddr);
} else {
LFS_IENTRY(ifp, fs, ino, bp);
daddr = ifp->if_daddr;
ifp->if_daddr = dbtofsb(fs, ndaddr);
error = LFS_BWRITE_LOG(bp); /* Ifile */
ifp->if_daddr = LFS_DBTOFSB(fs, ndaddr);
(void)LFS_BWRITE_LOG(bp); /* Ifile */
}
/*
@@ -945,8 +965,8 @@ lfs_update_iaddr(struct lfs *fs, struct segment *sp, struct inode *ip, daddr_t n
* (XXX should already be dirty?) and tell the caller to do it again.
*/
if (ip->i_number == LFS_IFILE_INUM) {
sn = dtosn(fs, fs->lfs_offset);
if (sntod(fs, sn) + btofsb(fs, fs->lfs_sumsize) ==
sn = lfs_dtosn(fs, fs->lfs_offset);
if (lfs_sntod(fs, sn) + lfs_btofsb(fs, fs->lfs_sumsize) ==
fs->lfs_offset) {
LFS_SEGENTRY(sup, fs, sn, bp);
KASSERT(bp->b_oflags & BO_DELWRI);
@@ -978,33 +998,33 @@ lfs_update_iaddr(struct lfs *fs, struct segment *sp, struct inode *ip, daddr_t n
* is actually written.
*/
if (daddr != LFS_UNUSED_DADDR) {
u_int32_t oldsn = dtosn(fs, daddr);
u_int32_t oldsn = lfs_dtosn(fs, daddr);
#ifdef DIAGNOSTIC
int ndupino = (sp->seg_number == oldsn) ? sp->ndupino : 0;
#endif
LFS_SEGENTRY(sup, fs, oldsn, bp);
#ifdef DIAGNOSTIC
if (sup->su_nbytes +
sizeof (struct ufs1_dinode) * ndupino
< sizeof (struct ufs1_dinode)) {
sizeof (struct ulfs1_dinode) * ndupino
< sizeof (struct ulfs1_dinode)) {
printf("lfs_writeinode: negative bytes "
"(segment %" PRIu32 " short by %d, "
"oldsn=%" PRIu32 ", cursn=%" PRIu32
", daddr=%" PRId64 ", su_nbytes=%u, "
"ndupino=%d)\n",
dtosn(fs, daddr),
(int)sizeof (struct ufs1_dinode) *
lfs_dtosn(fs, daddr),
(int)sizeof (struct ulfs1_dinode) *
(1 - sp->ndupino) - sup->su_nbytes,
oldsn, sp->seg_number, daddr,
(unsigned int)sup->su_nbytes,
sp->ndupino);
panic("lfs_writeinode: negative bytes");
sup->su_nbytes = sizeof (struct ufs1_dinode);
sup->su_nbytes = sizeof (struct ulfs1_dinode);
}
#endif
DLOG((DLOG_SU, "seg %d -= %d for ino %d inode\n",
dtosn(fs, daddr), sizeof (struct ufs1_dinode), ino));
sup->su_nbytes -= sizeof (struct ufs1_dinode);
lfs_dtosn(fs, daddr), sizeof (struct ulfs1_dinode), ino));
sup->su_nbytes -= sizeof (struct ulfs1_dinode);
redo_ifile |=
(ino == LFS_IFILE_INUM && !(bp->b_flags & B_GATHERED));
if (redo_ifile) {
@@ -1024,7 +1044,8 @@ int
lfs_writeinode(struct lfs *fs, struct segment *sp, struct inode *ip)
{
struct buf *bp;
struct ufs1_dinode *cdp;
struct ulfs1_dinode *cdp;
struct vnode *vp = ITOV(ip);
daddr_t daddr;
int32_t *daddrp; /* XXX ondisk32 */
int i, ndx;
@@ -1033,7 +1054,7 @@ lfs_writeinode(struct lfs *fs, struct segment *sp, struct inode *ip)
int count;
ASSERT_SEGLOCK(fs);
if (!(ip->i_flag & IN_ALLMOD))
if (!(ip->i_flag & IN_ALLMOD) && !(vp->v_uflag & VU_DIROP))
return (0);
/* Can't write ifile when writer is not set */
@@ -1047,7 +1068,7 @@ lfs_writeinode(struct lfs *fs, struct segment *sp, struct inode *ip)
* solid.
*/
count = 0;
while (ip->i_number == LFS_IFILE_INUM) {
while (vp == fs->lfs_ivnode) {
int redo = 0;
if (sp->idp == NULL && sp->ibp == NULL &&
@@ -1090,29 +1111,29 @@ lfs_writeinode(struct lfs *fs, struct segment *sp, struct inode *ip)
/* Get next inode block. */
daddr = fs->lfs_offset;
fs->lfs_offset += btofsb(fs, fs->lfs_ibsize);
fs->lfs_offset += lfs_btofsb(fs, fs->lfs_ibsize);
sp->ibp = *sp->cbpp++ =
getblk(VTOI(fs->lfs_ivnode)->i_devvp,
fsbtodb(fs, daddr), fs->lfs_ibsize, 0, 0);
LFS_FSBTODB(fs, daddr), fs->lfs_ibsize, 0, 0);
gotblk++;
/* Zero out inode numbers */
for (i = 0; i < INOPB(fs); ++i)
((struct ufs1_dinode *)sp->ibp->b_data)[i].di_inumber =
for (i = 0; i < LFS_INOPB(fs); ++i)
((struct ulfs1_dinode *)sp->ibp->b_data)[i].di_inumber =
0;
++sp->start_bpp;
fs->lfs_avail -= btofsb(fs, fs->lfs_ibsize);
fs->lfs_avail -= lfs_btofsb(fs, fs->lfs_ibsize);
/* Set remaining space counters. */
sp->seg_bytes_left -= fs->lfs_ibsize;
sp->sum_bytes_left -= sizeof(int32_t);
ndx = fs->lfs_sumsize / sizeof(int32_t) -
sp->ninodes / INOPB(fs) - 1;
sp->ninodes / LFS_INOPB(fs) - 1;
((int32_t *)(sp->segsum))[ndx] = daddr;
}
/* Check VU_DIROP in case there is a new file with no data blocks */
if (ITOV(ip)->v_uflag & VU_DIROP)
if (vp->v_uflag & VU_DIROP)
((SEGSUM *)(sp->segsum))->ss_flags |= (SS_DIROP|SS_CONT);
/* Update the inode times and copy the inode onto the inode page. */
@@ -1135,9 +1156,21 @@ lfs_writeinode(struct lfs *fs, struct segment *sp, struct inode *ip)
}
bp = sp->ibp;
cdp = ((struct ufs1_dinode *)bp->b_data) + (sp->ninodes % INOPB(fs));
cdp = ((struct ulfs1_dinode *)bp->b_data) + (sp->ninodes % LFS_INOPB(fs));
*cdp = *ip->i_din.ffs1_din;
/*
* This inode is on its way to disk; clear its VU_DIROP status when
* the write is complete.
*/
if (vp->v_uflag & VU_DIROP) {
if (!(sp->seg_flags & SEGM_CLEAN))
ip->i_flag |= IN_CDIROP;
else {
DLOG((DLOG_DIROP, "lfs_writeinode: not clearing dirop for cleaned ino %d\n", (int)ip->i_number));
}
}
/*
* If cleaning, link counts and directory file sizes cannot change,
* since those would be directory operations---even if the file
@@ -1146,9 +1179,9 @@ lfs_writeinode(struct lfs *fs, struct segment *sp, struct inode *ip)
* current values the next time we clean.
*/
if (sp->seg_flags & SEGM_CLEAN) {
if (ITOV(ip)->v_uflag & VU_DIROP) {
if (vp->v_uflag & VU_DIROP) {
cdp->di_nlink = ip->i_lfs_odnlink;
/* if (ITOV(ip)->v_type == VDIR) */
/* if (vp->v_type == VDIR) */
cdp->di_size = ip->i_lfs_osize;
}
} else {
@@ -1174,8 +1207,8 @@ lfs_writeinode(struct lfs *fs, struct segment *sp, struct inode *ip)
*/
/* Check file size based on highest allocated block */
if (((ip->i_ffs1_mode & IFMT) == IFREG ||
(ip->i_ffs1_mode & IFMT) == IFDIR) &&
if (((ip->i_ffs1_mode & LFS_IFMT) == LFS_IFREG ||
(ip->i_ffs1_mode & LFS_IFMT) == LFS_IFDIR) &&
ip->i_size > ((ip->i_lfs_hiblk + 1) << fs->lfs_bshift)) {
cdp->di_size = (ip->i_lfs_hiblk + 1) << fs->lfs_bshift;
DLOG((DLOG_SEG, "lfs_writeinode: ino %d size %" PRId64 " -> %"
@@ -1185,7 +1218,7 @@ lfs_writeinode(struct lfs *fs, struct segment *sp, struct inode *ip)
DLOG((DLOG_SEG, "lfs_writeinode: cleansing ino %d eff %d != nblk %d)"
" at %x\n", ip->i_number, ip->i_lfs_effnblks,
ip->i_ffs1_blocks, fs->lfs_offset));
for (daddrp = cdp->di_db; daddrp < cdp->di_ib + NIADDR;
for (daddrp = cdp->di_db; daddrp < cdp->di_ib + ULFS_NIADDR;
daddrp++) {
if (*daddrp == UNWRITTEN) {
DLOG((DLOG_SEG, "lfs_writeinode: wiping UNWRITTEN\n"));
@@ -1200,12 +1233,12 @@ lfs_writeinode(struct lfs *fs, struct segment *sp, struct inode *ip)
* This should be identical to the check in lfs_vget().
*/
for (i = (cdp->di_size + fs->lfs_bsize - 1) >> fs->lfs_bshift;
i < NDADDR; i++) {
i < ULFS_NDADDR; i++) {
KASSERT(i >= 0);
if ((cdp->di_mode & IFMT) == IFLNK)
if ((cdp->di_mode & LFS_IFMT) == LFS_IFLNK)
continue;
if (((cdp->di_mode & IFMT) == IFBLK ||
(cdp->di_mode & IFMT) == IFCHR) && i == 0)
if (((cdp->di_mode & LFS_IFMT) == LFS_IFBLK ||
(cdp->di_mode & LFS_IFMT) == LFS_IFCHR) && i == 0)
continue;
if (cdp->di_db[i] != 0) {
# ifdef DEBUG
@@ -1233,8 +1266,8 @@ lfs_writeinode(struct lfs *fs, struct segment *sp, struct inode *ip)
if (ip->i_number == LFS_IFILE_INUM) {
/* We know sp->idp == NULL */
sp->idp = ((struct ufs1_dinode *)bp->b_data) +
(sp->ninodes % INOPB(fs));
sp->idp = ((struct ulfs1_dinode *)bp->b_data) +
(sp->ninodes % LFS_INOPB(fs));
/* Not dirty any more */
mutex_enter(&lfs_lock);
@@ -1253,7 +1286,7 @@ lfs_writeinode(struct lfs *fs, struct segment *sp, struct inode *ip)
++((SEGSUM *)(sp->segsum))->ss_ninos;
/* If this page is full, set flag to allocate a new page. */
if (++sp->ninodes % INOPB(fs) == 0)
if (++sp->ninodes % LFS_INOPB(fs) == 0)
sp->ibp = NULL;
redo_ifile = lfs_update_iaddr(fs, sp, ip, bp->b_blkno);
@@ -1382,7 +1415,7 @@ loop:
DLOG((DLOG_SEG, "lfs_gather: lbn %" PRId64
" blk %" PRId64 " not B_LOCKED\n",
bp->b_lblkno,
dbtofsb(fs, bp->b_blkno)));
LFS_DBTOFSB(fs, bp->b_blkno)));
VOP_PRINT(bp->b_vp);
panic("lfs_gather: bp not B_LOCKED");
}
@@ -1414,7 +1447,7 @@ loop:
/*
* Change the given block's address to ndaddr, finding its previous
* location using ufs_bmaparray().
* location using ulfs_bmaparray().
*
* Account for this change in the segment table.
*
@@ -1426,7 +1459,7 @@ lfs_update_single(struct lfs *fs, struct segment *sp,
{
SEGUSE *sup;
struct buf *bp;
struct indir a[NIADDR + 2], *ap;
struct indir a[ULFS_NIADDR + 2], *ap;
struct inode *ip;
daddr_t daddr, ooff;
int num, error;
@@ -1436,16 +1469,16 @@ lfs_update_single(struct lfs *fs, struct segment *sp,
KASSERT(sp == NULL || sp->vp == vp);
ip = VTOI(vp);
error = ufs_bmaparray(vp, lbn, &daddr, a, &num, NULL, NULL);
error = ulfs_bmaparray(vp, lbn, &daddr, a, &num, NULL, NULL);
if (error)
panic("lfs_updatemeta: ufs_bmaparray returned %d", error);
panic("lfs_updatemeta: ulfs_bmaparray returned %d", error);
daddr = (daddr_t)((int32_t)daddr); /* XXX ondisk32 */
KASSERT(daddr <= LFS_MAX_DADDR);
if (daddr > 0)
daddr = dbtofsb(fs, daddr);
daddr = LFS_DBTOFSB(fs, daddr);
bb = numfrags(fs, size);
bb = lfs_numfrags(fs, size);
switch (num) {
case 0:
ooff = ip->i_ffs1_db[lbn];
@@ -1454,7 +1487,7 @@ lfs_update_single(struct lfs *fs, struct segment *sp,
ip->i_ffs1_blocks += bb;
else {
/* possible fragment truncation or extension */
obb = btofsb(fs, ip->i_lfs_fragsize[lbn]);
obb = lfs_btofsb(fs, ip->i_lfs_fragsize[lbn]);
ip->i_ffs1_blocks += (bb - obb);
}
ip->i_ffs1_db[lbn] = ndaddr;
@@ -1500,7 +1533,7 @@ lfs_update_single(struct lfs *fs, struct segment *sp,
* and location.
*/
if (daddr > 0) {
u_int32_t oldsn = dtosn(fs, daddr);
u_int32_t oldsn = lfs_dtosn(fs, daddr);
#ifdef DIAGNOSTIC
int ndupino;
@@ -1511,19 +1544,19 @@ lfs_update_single(struct lfs *fs, struct segment *sp,
}
#endif
KASSERT(oldsn < fs->lfs_nseg);
if (lbn >= 0 && lbn < NDADDR)
if (lbn >= 0 && lbn < ULFS_NDADDR)
osize = ip->i_lfs_fragsize[lbn];
else
osize = fs->lfs_bsize;
LFS_SEGENTRY(sup, fs, oldsn, bp);
#ifdef DIAGNOSTIC
if (sup->su_nbytes + sizeof (struct ufs1_dinode) * ndupino
if (sup->su_nbytes + sizeof (struct ulfs1_dinode) * ndupino
< osize) {
printf("lfs_updatemeta: negative bytes "
"(segment %" PRIu32 " short by %" PRId64
")\n", dtosn(fs, daddr),
")\n", lfs_dtosn(fs, daddr),
(int64_t)osize -
(sizeof (struct ufs1_dinode) * ndupino +
(sizeof (struct ulfs1_dinode) * ndupino +
sup->su_nbytes));
printf("lfs_updatemeta: ino %llu, lbn %" PRId64
", addr = 0x%" PRIx64 "\n",
@@ -1531,12 +1564,12 @@ lfs_update_single(struct lfs *fs, struct segment *sp,
printf("lfs_updatemeta: ndupino=%d\n", ndupino);
panic("lfs_updatemeta: negative bytes");
sup->su_nbytes = osize -
sizeof (struct ufs1_dinode) * ndupino;
sizeof (struct ulfs1_dinode) * ndupino;
}
#endif
DLOG((DLOG_SU, "seg %" PRIu32 " -= %d for ino %d lbn %" PRId64
" db 0x%" PRIx64 "\n",
dtosn(fs, daddr), osize,
lfs_dtosn(fs, daddr), osize,
ip->i_number, lbn, daddr));
sup->su_nbytes -= osize;
if (!(bp->b_flags & B_GATHERED)) {
@@ -1551,7 +1584,7 @@ lfs_update_single(struct lfs *fs, struct segment *sp,
* segment no longer owns it, we can forget about its
* old size.
*/
if (lbn >= 0 && lbn < NDADDR)
if (lbn >= 0 && lbn < ULFS_NDADDR)
ip->i_lfs_fragsize[lbn] = size;
}
@@ -1631,7 +1664,7 @@ lfs_updatemeta(struct segment *sp)
lbn = *sp->start_lbp;
KASSERT(sbp->b_lblkno == lbn);
sbp->b_blkno = fsbtodb(fs, fs->lfs_offset);
sbp->b_blkno = LFS_FSBTODB(fs, fs->lfs_offset);
/*
* If we write a frag in the wrong place, the cleaner won't
@@ -1652,7 +1685,7 @@ lfs_updatemeta(struct segment *sp)
for (bytesleft = sbp->b_bcount; bytesleft > 0;
bytesleft -= fs->lfs_bsize) {
size = MIN(bytesleft, fs->lfs_bsize);
bb = numfrags(fs, size);
bb = lfs_numfrags(fs, size);
lbn = *sp->start_lbp++;
lfs_update_single(fs, sp, sp->vp, lbn, fs->lfs_offset,
size);
@@ -1677,7 +1710,7 @@ lfs_rewind(struct lfs *fs, int newsn)
ASSERT_SEGLOCK(fs);
osn = dtosn(fs, fs->lfs_offset);
osn = lfs_dtosn(fs, fs->lfs_offset);
if (osn < newsn)
return 0;
@@ -1733,8 +1766,8 @@ lfs_initseg(struct lfs *fs)
repeat = 1;
fs->lfs_offset = fs->lfs_curseg;
sp->seg_number = dtosn(fs, fs->lfs_curseg);
sp->seg_bytes_left = fsbtob(fs, fs->lfs_fsbpseg);
sp->seg_number = lfs_dtosn(fs, fs->lfs_curseg);
sp->seg_bytes_left = lfs_fsbtob(fs, fs->lfs_fsbpseg);
/*
* If the segment contains a superblock, update the offset
@@ -1742,21 +1775,21 @@ lfs_initseg(struct lfs *fs)
*/
LFS_SEGENTRY(sup, fs, sp->seg_number, bp);
if (sup->su_flags & SEGUSE_SUPERBLOCK) {
fs->lfs_offset += btofsb(fs, LFS_SBPAD);
fs->lfs_offset += lfs_btofsb(fs, LFS_SBPAD);
sp->seg_bytes_left -= LFS_SBPAD;
}
brelse(bp, 0);
/* Segment zero could also contain the labelpad */
if (fs->lfs_version > 1 && sp->seg_number == 0 &&
fs->lfs_start < btofsb(fs, LFS_LABELPAD)) {
fs->lfs_start < lfs_btofsb(fs, LFS_LABELPAD)) {
fs->lfs_offset +=
btofsb(fs, LFS_LABELPAD) - fs->lfs_start;
lfs_btofsb(fs, LFS_LABELPAD) - fs->lfs_start;
sp->seg_bytes_left -=
LFS_LABELPAD - fsbtob(fs, fs->lfs_start);
LFS_LABELPAD - lfs_fsbtob(fs, fs->lfs_start);
}
} else {
sp->seg_number = dtosn(fs, fs->lfs_curseg);
sp->seg_bytes_left = fsbtob(fs, fs->lfs_fsbpseg -
sp->seg_number = lfs_dtosn(fs, fs->lfs_curseg);
sp->seg_bytes_left = lfs_fsbtob(fs, fs->lfs_fsbpseg -
(fs->lfs_offset - fs->lfs_curseg));
}
fs->lfs_lastpseg = fs->lfs_offset;
@@ -1786,12 +1819,12 @@ lfs_initseg(struct lfs *fs)
/* Get a new buffer for SEGSUM */
sbp = lfs_newbuf(fs, VTOI(fs->lfs_ivnode)->i_devvp,
fsbtodb(fs, fs->lfs_offset), fs->lfs_sumsize, LFS_NB_SUMMARY);
LFS_FSBTODB(fs, fs->lfs_offset), fs->lfs_sumsize, LFS_NB_SUMMARY);
/* ... and enter it into the buffer list. */
*sp->cbpp = sbp;
sp->cbpp++;
fs->lfs_offset += btofsb(fs, fs->lfs_sumsize);
fs->lfs_offset += lfs_btofsb(fs, fs->lfs_sumsize);
sp->start_bpp = sp->cbpp;
@@ -1865,14 +1898,14 @@ lfs_newseg(struct lfs *fs)
fs->lfs_wrapstatus = LFS_WRAP_GOING;
mutex_exit(&lfs_lock);
LFS_SEGENTRY(sup, fs, dtosn(fs, fs->lfs_nextseg), bp);
LFS_SEGENTRY(sup, fs, lfs_dtosn(fs, fs->lfs_nextseg), bp);
DLOG((DLOG_SU, "lfs_newseg: seg %d := 0 in newseg\n",
dtosn(fs, fs->lfs_nextseg)));
lfs_dtosn(fs, fs->lfs_nextseg)));
sup->su_flags |= SEGUSE_DIRTY | SEGUSE_ACTIVE;
sup->su_nbytes = 0;
sup->su_nsums = 0;
sup->su_ninos = 0;
LFS_WRITESEGENTRY(sup, fs, dtosn(fs, fs->lfs_nextseg), bp);
LFS_WRITESEGENTRY(sup, fs, lfs_dtosn(fs, fs->lfs_nextseg), bp);
LFS_CLEANERINFO(cip, fs, bp);
--cip->clean;
@@ -1883,7 +1916,7 @@ lfs_newseg(struct lfs *fs)
fs->lfs_lastseg = fs->lfs_curseg;
fs->lfs_curseg = fs->lfs_nextseg;
skip_inval = 1;
for (sn = curseg = dtosn(fs, fs->lfs_curseg) + fs->lfs_interleave;;) {
for (sn = curseg = lfs_dtosn(fs, fs->lfs_curseg) + fs->lfs_interleave;;) {
sn = (sn + 1) % fs->lfs_nseg;
if (sn == curseg) {
@@ -1908,7 +1941,7 @@ lfs_newseg(struct lfs *fs)
lfs_unset_inval_all(fs);
++fs->lfs_nactive;
fs->lfs_nextseg = sntod(fs, sn);
fs->lfs_nextseg = lfs_sntod(fs, sn);
if (lfs_dostats) {
++lfs_stats.segsused;
}
@@ -1988,6 +2021,12 @@ lfs_writeseg(struct lfs *fs, struct segment *sp)
if (sp->seg_flags & SEGM_CLEAN)
ssp->ss_flags |= SS_CLEAN;
/* Note if we are writing to reclaim */
if (sp->seg_flags & SEGM_RECLAIM) {
ssp->ss_flags |= SS_RECLAIM;
ssp->ss_reclino = fs->lfs_reclino;
}
devvp = VTOI(fs->lfs_ivnode)->i_devvp;
/* Update the segment usage information. */
@@ -2016,11 +2055,11 @@ lfs_writeseg(struct lfs *fs, struct segment *sp)
}
#endif /* DEBUG */
ninos = (ssp->ss_ninos + INOPB(fs) - 1) / INOPB(fs);
ninos = (ssp->ss_ninos + LFS_INOPB(fs) - 1) / LFS_INOPB(fs);
DLOG((DLOG_SU, "seg %d += %d for %d inodes\n",
sp->seg_number, ssp->ss_ninos * sizeof (struct ufs1_dinode),
sp->seg_number, ssp->ss_ninos * sizeof (struct ulfs1_dinode),
ssp->ss_ninos));
sup->su_nbytes += ssp->ss_ninos * sizeof (struct ufs1_dinode);
sup->su_nbytes += ssp->ss_ninos * sizeof (struct ulfs1_dinode);
/* sup->su_nbytes += fs->lfs_sumsize; */
if (fs->lfs_version == 1)
sup->su_olastmod = time_second;
@@ -2028,7 +2067,7 @@ lfs_writeseg(struct lfs *fs, struct segment *sp)
sup->su_lastmod = time_second;
sup->su_ninos += ninos;
++sup->su_nsums;
fs->lfs_avail -= btofsb(fs, fs->lfs_sumsize);
fs->lfs_avail -= lfs_btofsb(fs, fs->lfs_sumsize);
do_again = !(bp->b_flags & B_GATHERED);
LFS_WRITESEGENTRY(sup, fs, sp->seg_number, bp); /* Ifile */
@@ -2116,7 +2155,7 @@ lfs_writeseg(struct lfs *fs, struct segment *sp)
* segment.
*/
fs->lfs_avail -=
btofsb(fs, bp->b_bcount);
lfs_btofsb(fs, bp->b_bcount);
}
} else {
lfs_freebuf(fs, newbp);
@@ -2176,10 +2215,10 @@ lfs_writeseg(struct lfs *fs, struct segment *sp)
fs->lfs_sumsize - sizeof(ssp->ss_sumsum));
mutex_enter(&lfs_lock);
fs->lfs_bfree -= (btofsb(fs, ninos * fs->lfs_ibsize) +
btofsb(fs, fs->lfs_sumsize));
fs->lfs_dmeta += (btofsb(fs, ninos * fs->lfs_ibsize) +
btofsb(fs, fs->lfs_sumsize));
fs->lfs_bfree -= (lfs_btofsb(fs, ninos * fs->lfs_ibsize) +
lfs_btofsb(fs, fs->lfs_sumsize));
fs->lfs_dmeta += (lfs_btofsb(fs, ninos * fs->lfs_ibsize) +
lfs_btofsb(fs, fs->lfs_sumsize));
mutex_exit(&lfs_lock);
/*
@@ -2209,7 +2248,7 @@ lfs_writeseg(struct lfs *fs, struct segment *sp)
/ sizeof(int32_t)) {
panic("lfs_writeseg: real bpp overwrite");
}
if (bpp - sp->bpp > segsize(fs) / fs->lfs_fsize) {
if (bpp - sp->bpp > lfs_segsize(fs) / fs->lfs_fsize) {
panic("lfs_writeseg: theoretical bpp overwrite");
}
#endif
@@ -2242,7 +2281,7 @@ lfs_writeseg(struct lfs *fs, struct segment *sp)
cl->flags |= LFS_CL_MALLOC;
}
#ifdef DIAGNOSTIC
if (dtosn(fs, dbtofsb(fs, bp->b_blkno +
if (lfs_dtosn(fs, LFS_DBTOFSB(fs, bp->b_blkno +
btodb(bp->b_bcount - 1))) !=
sp->seg_number) {
printf("blk size %d daddr %" PRIx64
@@ -2351,7 +2390,7 @@ lfs_writesuper(struct lfs *fs, daddr_t daddr)
/* Checksum the superblock and copy it into a buffer. */
fs->lfs_cksum = lfs_sb_cksum(&(fs->lfs_dlfs));
bp = lfs_newbuf(fs, devvp,
fsbtodb(fs, daddr), LFS_SBPAD, LFS_NB_SBLOCK);
LFS_FSBTODB(fs, daddr), LFS_SBPAD, LFS_NB_SBLOCK);
memset((char *)bp->b_data + sizeof(struct dlfs), 0,
LFS_SBPAD - sizeof(struct dlfs));
*(struct dlfs *)bp->b_data = fs->lfs_dlfs;
@@ -2415,7 +2454,7 @@ lfs_match_indir(struct lfs *fs, struct buf *bp)
ASSERT_SEGLOCK(fs);
lbn = bp->b_lblkno;
return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 0);
return (lbn < 0 && (-lbn - ULFS_NDADDR) % LFS_NINDIR(fs) == 0);
}
int
@@ -2425,7 +2464,7 @@ lfs_match_dindir(struct lfs *fs, struct buf *bp)
ASSERT_SEGLOCK(fs);
lbn = bp->b_lblkno;
return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 1);
return (lbn < 0 && (-lbn - ULFS_NDADDR) % LFS_NINDIR(fs) == 1);
}
int
@@ -2435,7 +2474,7 @@ lfs_match_tindir(struct lfs *fs, struct buf *bp)
ASSERT_SEGLOCK(fs);
lbn = bp->b_lblkno;
return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 2);
return (lbn < 0 && (-lbn - ULFS_NDADDR) % LFS_NINDIR(fs) == 2);
}
static void
@@ -2561,8 +2600,8 @@ lfs_cluster_aiodone(struct buf *bp)
* XXX KS - Shouldn't we set *both* if both types
* of blocks are present (traverse the dirty list?)
*/
mutex_enter(&lfs_lock);
mutex_enter(vp->v_interlock);
mutex_enter(&lfs_lock);
if (vp != devvp && vp->v_numoutput == 0 &&
(fbp = LIST_FIRST(&vp->v_dirtyblkhd)) != NULL) {
ip = VTOI(vp);
@@ -2574,8 +2613,8 @@ lfs_cluster_aiodone(struct buf *bp)
LFS_SET_UINO(ip, IN_MODIFIED);
}
cv_broadcast(&vp->v_cv);
mutex_exit(vp->v_interlock);
mutex_exit(&lfs_lock);
mutex_exit(vp->v_interlock);
}
/* Fix up the cluster buffer, and release it */
@@ -2720,7 +2759,6 @@ lfs_shellsort(struct buf **bp_array, int32_t *lb_array, int nmemb, int size)
int
lfs_vref(struct vnode *vp)
{
int error;
struct lfs *fs;
KASSERT(mutex_owned(vp->v_interlock));
@@ -2734,12 +2772,13 @@ lfs_vref(struct vnode *vp)
* being able to flush all of the pages from this vnode, which
* will cause it to panic. So, return 0 if a flush is in progress.
*/
error = vget(vp, LK_NOWAIT);
if (error == EBUSY && IS_FLUSHING(VTOI(vp)->i_lfs, vp)) {
++fs->lfs_flushvp_fakevref;
return 0;
}
return error;
if (IS_FLUSHING(VTOI(vp)->i_lfs, vp)) {
++fs->lfs_flushvp_fakevref;
mutex_exit(vp->v_interlock);
return 0;
}
return vget(vp, LK_NOWAIT);
}
/*
@@ -2762,9 +2801,8 @@ lfs_vunref(struct vnode *vp)
return;
}
/* does not call inactive */
mutex_enter(vp->v_interlock);
vrelel(vp, 0);
/* does not call inactive XXX sure it does XXX */
vrele(vp);
}
/*
@@ -2781,9 +2819,9 @@ lfs_vunref_head(struct vnode *vp)
ASSERT_SEGLOCK(VTOI(vp)->i_lfs);
/* does not call inactive, inserts non-held vnode at head of freelist */
mutex_enter(vp->v_interlock);
vrelel(vp, 0);
/* does not call inactive XXX sure it does XXX,
inserts non-held vnode at head of freelist */
vrele(vp);
}
+10 -8
View File
@@ -1,4 +1,4 @@
/* $NetBSD: lfs_subr.c,v 1.76 2010/06/25 10:03:52 hannken Exp $ */
/* $NetBSD: lfs_subr.c,v 1.80 2013/07/28 01:05:52 dholland Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -60,7 +60,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_subr.c,v 1.76 2010/06/25 10:03:52 hannken Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_subr.c,v 1.80 2013/07/28 01:05:52 dholland Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -72,8 +72,9 @@ __KERNEL_RCSID(0, "$NetBSD: lfs_subr.c,v 1.76 2010/06/25 10:03:52 hannken Exp $"
#include <sys/proc.h>
#include <sys/kauth.h>
#include <ufs/ufs/inode.h>
#include <ufs/lfs/ulfs_inode.h>
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_kernel.h>
#include <ufs/lfs/lfs_extern.h>
#include <uvm/uvm.h>
@@ -144,7 +145,7 @@ lfs_setup_resblks(struct lfs *fs)
pool_init(&fs->lfs_segpool, sizeof(struct segment), 0, 0, 0,
"lfssegpool", &pool_allocator_nointr, IPL_NONE);
maxbpp = ((fs->lfs_sumsize - SEGSUM_SIZE(fs)) / sizeof(int32_t) + 2);
maxbpp = MIN(maxbpp, segsize(fs) / fs->lfs_fsize + 2);
maxbpp = MIN(maxbpp, lfs_segsize(fs) / fs->lfs_fsize + 2);
pool_init(&fs->lfs_bpppool, maxbpp * sizeof(struct buf *), 0, 0, 0,
"lfsbpppl", &pool_allocator_nointr, IPL_NONE);
}
@@ -335,6 +336,7 @@ lfs_seglock(struct lfs *fs, unsigned long flags)
*/
mutex_enter(&lfs_lock);
++fs->lfs_iocount;
fs->lfs_startseg = fs->lfs_curseg;
mutex_exit(&lfs_lock);
return 0;
}
@@ -361,7 +363,7 @@ lfs_unmark_dirop(struct lfs *fs)
for (ip = TAILQ_FIRST(&fs->lfs_dchainhd); ip != NULL; ip = nip) {
nip = TAILQ_NEXT(ip, i_lfs_dchain);
vp = ITOV(ip);
if ((VTOI(vp)->i_flag & (IN_ADIROP | IN_ALLMOD)) == 0) {
if ((ip->i_flag & (IN_ADIROP | IN_CDIROP)) == IN_CDIROP) {
--lfs_dirvcount;
--fs->lfs_dirvcount;
vp->v_uflag &= ~VU_DIROP;
@@ -372,6 +374,7 @@ lfs_unmark_dirop(struct lfs *fs)
vrele(vp);
mutex_enter(&lfs_lock);
fs->lfs_unlockvp = NULL;
ip->i_flag &= ~IN_CDIROP;
}
}
@@ -437,8 +440,7 @@ lfs_segunlock(struct lfs *fs)
mutex_enter(&lfs_lock);
KASSERT(LFS_SEGLOCK_HELD(fs));
if (fs->lfs_seglock == 1) {
if ((sp->seg_flags & (SEGM_PROT | SEGM_CLEAN)) == 0 &&
LFS_STARVED_FOR_SEGS(fs) == 0)
if ((sp->seg_flags & (SEGM_PROT | SEGM_CLEAN)) == 0)
do_unmark_dirop = 1;
mutex_exit(&lfs_lock);
sync = sp->seg_flags & SEGM_SYNC;
@@ -448,7 +450,7 @@ lfs_segunlock(struct lfs *fs)
KASSERT(sp->cbpp == sp->bpp + 1);
/* Free allocated segment summary */
fs->lfs_offset -= btofsb(fs, fs->lfs_sumsize);
fs->lfs_offset -= lfs_btofsb(fs, fs->lfs_sumsize);
bp = *sp->bpp;
lfs_freebuf(fs, bp);
+86 -70
View File
@@ -1,4 +1,4 @@
/* $NetBSD: lfs_syscalls.c,v 1.139 2011/06/12 03:36:01 rmind Exp $ */
/* $NetBSD: lfs_syscalls.c,v 1.150 2013/10/29 09:53:51 hannken Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003, 2007, 2007, 2008
@@ -61,7 +61,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_syscalls.c,v 1.139 2011/06/12 03:36:01 rmind Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_syscalls.c,v 1.150 2013/10/29 09:53:51 hannken Exp $");
#ifndef LFS
# define LFS /* for prototypes in syscallargs.h */
@@ -77,11 +77,12 @@ __KERNEL_RCSID(0, "$NetBSD: lfs_syscalls.c,v 1.139 2011/06/12 03:36:01 rmind Exp
#include <sys/kauth.h>
#include <sys/syscallargs.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/ufs_extern.h>
#include <ufs/lfs/ulfs_inode.h>
#include <ufs/lfs/ulfsmount.h>
#include <ufs/lfs/ulfs_extern.h>
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_kernel.h>
#include <ufs/lfs/lfs_extern.h>
struct buf *lfs_fakebuf(struct lfs *, struct vnode *, int, size_t, void *);
@@ -117,8 +118,9 @@ sys_lfs_markv(struct lwp *l, const struct sys_lfs_markv_args *uap, register_t *r
struct lfs *fs;
struct mount *mntp;
if ((error = kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
NULL)) != 0)
error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_LFS,
KAUTH_REQ_SYSTEM_LFS_MARKV, NULL, NULL, NULL);
if (error)
return (error);
if ((error = copyin(SCARG(uap, fsidp), &fsid, sizeof(fsid_t))) != 0)
@@ -126,7 +128,7 @@ sys_lfs_markv(struct lwp *l, const struct sys_lfs_markv_args *uap, register_t *r
if ((mntp = vfs_getvfs(fsidp)) == NULL)
return (ENOENT);
fs = VFSTOUFS(mntp)->um_lfs;
fs = VFSTOULFS(mntp)->um_lfs;
blkcnt = SCARG(uap, blkcnt);
if ((u_int) blkcnt > LFS_MARKV_MAXBLKCNT)
@@ -162,8 +164,9 @@ sys_lfs_markv(struct lwp *l, const struct sys_lfs_markv_args *uap, register_t *r
struct lfs *fs;
struct mount *mntp;
if ((error = kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
NULL)) != 0)
error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_LFS,
KAUTH_REQ_SYSTEM_LFS_MARKV, NULL, NULL, NULL);
if (error)
return (error);
if ((error = copyin(SCARG(uap, fsidp), &fsid, sizeof(fsid_t))) != 0)
@@ -171,7 +174,7 @@ sys_lfs_markv(struct lwp *l, const struct sys_lfs_markv_args *uap, register_t *r
if ((mntp = vfs_getvfs(&fsid)) == NULL)
return (ENOENT);
fs = VFSTOUFS(mntp)->um_lfs;
fs = VFSTOULFS(mntp)->um_lfs;
blkcnt = SCARG(uap, blkcnt);
if ((u_int) blkcnt > LFS_MARKV_MAXBLKCNT)
@@ -242,12 +245,12 @@ lfs_markv(struct proc *p, fsid_t *fsidp, BLOCK_INFO *blkiov,
if ((mntp = vfs_getvfs(fsidp)) == NULL)
return (ENOENT);
fs = VFSTOUFS(mntp)->um_lfs;
fs = VFSTOULFS(mntp)->um_lfs;
if (fs->lfs_ronly)
return EROFS;
maxino = (fragstoblks(fs, VTOI(fs->lfs_ivnode)->i_ffs1_blocks) -
maxino = (lfs_fragstoblks(fs, VTOI(fs->lfs_ivnode)->i_ffs1_blocks) -
fs->lfs_cleansz - fs->lfs_segtabsz) * fs->lfs_ifpb;
cnt = blkcnt;
@@ -323,7 +326,7 @@ lfs_markv(struct proc *p, fsid_t *fsidp, BLOCK_INFO *blkiov,
DLOG((DLOG_CLEAN, "lfs_markv: lfs_fastvget"
" failed with %d (ino %d, segment %d)\n",
error, blkp->bi_inode,
dtosn(fs, blkp->bi_daddr)));
lfs_dtosn(fs, blkp->bi_daddr)));
/*
* If we got EAGAIN, that means that the
* Inode was locked. This is
@@ -389,13 +392,13 @@ lfs_markv(struct proc *p, fsid_t *fsidp, BLOCK_INFO *blkiov,
b_daddr = 0;
if (VOP_BMAP(vp, blkp->bi_lbn, NULL, &b_daddr, NULL) ||
dbtofsb(fs, b_daddr) != blkp->bi_daddr)
LFS_DBTOFSB(fs, b_daddr) != blkp->bi_daddr)
{
if (dtosn(fs, dbtofsb(fs, b_daddr)) ==
dtosn(fs, blkp->bi_daddr))
if (lfs_dtosn(fs, LFS_DBTOFSB(fs, b_daddr)) ==
lfs_dtosn(fs, blkp->bi_daddr))
{
DLOG((DLOG_CLEAN, "lfs_markv: wrong da same seg: %llx vs %llx\n",
(long long)blkp->bi_daddr, (long long)dbtofsb(fs, b_daddr)));
(long long)blkp->bi_daddr, (long long)LFS_DBTOFSB(fs, b_daddr)));
}
do_again++;
continue;
@@ -407,11 +410,11 @@ lfs_markv(struct proc *p, fsid_t *fsidp, BLOCK_INFO *blkiov,
* counterparts.
*/
if (blkp->bi_lbn >= 0)
obsize = blksize(fs, ip, blkp->bi_lbn);
obsize = lfs_blksize(fs, ip, blkp->bi_lbn);
else
obsize = fs->lfs_bsize;
/* Check for fragment size change */
if (blkp->bi_lbn >= 0 && blkp->bi_lbn < NDADDR) {
if (blkp->bi_lbn >= 0 && blkp->bi_lbn < ULFS_NDADDR) {
obsize = ip->i_lfs_fragsize[blkp->bi_lbn];
}
if (obsize != blkp->bi_size) {
@@ -436,7 +439,7 @@ lfs_markv(struct proc *p, fsid_t *fsidp, BLOCK_INFO *blkiov,
bp = lfs_fakebuf(fs, vp, blkp->bi_lbn,
blkp->bi_size, blkp->bi_bp);
/* Pretend we used bread() to get it */
bp->b_blkno = fsbtodb(fs, blkp->bi_daddr);
bp->b_blkno = LFS_FSBTODB(fs, blkp->bi_daddr);
} else {
/* Indirect block or ifile */
if (blkp->bi_size != fs->lfs_bsize &&
@@ -469,7 +472,7 @@ lfs_markv(struct proc *p, fsid_t *fsidp, BLOCK_INFO *blkiov,
/*
* XXX should account indirect blocks and ifile pages as well
*/
if (nblkwritten + lblkno(fs, ninowritten * sizeof (struct ufs1_dinode))
if (nblkwritten + lfs_lblkno(fs, ninowritten * sizeof (struct ulfs1_dinode))
> LFS_MARKV_MAX_BLOCKS) {
DLOG((DLOG_CLEAN, "lfs_markv: writing %d blks %d inos\n",
nblkwritten, ninowritten));
@@ -521,7 +524,6 @@ err2:
*/
err3:
KERNEL_UNLOCK_ONE(NULL);
/*
* XXX should do segwrite here anyway?
*/
@@ -564,8 +566,9 @@ sys_lfs_bmapv(struct lwp *l, const struct sys_lfs_bmapv_args *uap, register_t *r
struct lfs *fs;
struct mount *mntp;
if ((error = kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
NULL)) != 0)
error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_LFS,
KAUTH_REQ_SYSTEM_LFS_BMAPV, NULL, NULL, NULL);
if (error)
return (error);
if ((error = copyin(SCARG(uap, fsidp), &fsid, sizeof(fsid_t))) != 0)
@@ -573,7 +576,7 @@ sys_lfs_bmapv(struct lwp *l, const struct sys_lfs_bmapv_args *uap, register_t *r
if ((mntp = vfs_getvfs(&fsid)) == NULL)
return (ENOENT);
fs = VFSTOUFS(mntp)->um_lfs;
fs = VFSTOULFS(mntp)->um_lfs;
blkcnt = SCARG(uap, blkcnt);
if ((u_int) blkcnt > SIZE_T_MAX / sizeof(BLOCK_INFO))
@@ -608,8 +611,9 @@ sys_lfs_bmapv(struct lwp *l, const struct sys_lfs_bmapv_args *uap, register_t *r
struct lfs *fs;
struct mount *mntp;
if ((error = kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
NULL)) != 0)
error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_LFS,
KAUTH_REQ_SYSTEM_LFS_BMAPV, NULL, NULL, NULL);
if (error)
return (error);
if ((error = copyin(SCARG(uap, fsidp), &fsid, sizeof(fsid_t))) != 0)
@@ -617,7 +621,7 @@ sys_lfs_bmapv(struct lwp *l, const struct sys_lfs_bmapv_args *uap, register_t *r
if ((mntp = vfs_getvfs(&fsid)) == NULL)
return (ENOENT);
fs = VFSTOUFS(mntp)->um_lfs;
fs = VFSTOULFS(mntp)->um_lfs;
blkcnt = SCARG(uap, blkcnt);
if ((size_t) blkcnt > SIZE_T_MAX / sizeof(BLOCK_INFO))
@@ -669,7 +673,7 @@ lfs_bmapv(struct proc *p, fsid_t *fsidp, BLOCK_INFO *blkiov, int blkcnt)
struct inode *ip = NULL;
struct lfs *fs;
struct mount *mntp;
struct ufsmount *ump;
struct ulfsmount *ump;
struct vnode *vp;
ino_t lastino;
daddr_t v_daddr;
@@ -681,13 +685,13 @@ lfs_bmapv(struct proc *p, fsid_t *fsidp, BLOCK_INFO *blkiov, int blkcnt)
if ((mntp = vfs_getvfs(fsidp)) == NULL)
return (ENOENT);
ump = VFSTOUFS(mntp);
ump = VFSTOULFS(mntp);
if ((error = vfs_busy(mntp, NULL)) != 0)
return (error);
cnt = blkcnt;
fs = VFSTOUFS(mntp)->um_lfs;
fs = VFSTOULFS(mntp)->um_lfs;
error = 0;
@@ -708,6 +712,8 @@ lfs_bmapv(struct proc *p, fsid_t *fsidp, BLOCK_INFO *blkiov, int blkcnt)
*/
if (v_daddr != LFS_UNUSED_DADDR) {
lfs_vunref(vp);
if (VTOI(vp)->i_lfs_iflags & LFSI_BMAP)
vrecycle(vp, NULL);
numrefed--;
}
@@ -730,19 +736,19 @@ lfs_bmapv(struct proc *p, fsid_t *fsidp, BLOCK_INFO *blkiov, int blkcnt)
* A regular call to VFS_VGET could deadlock
* here. Instead, we try an unlocked access.
*/
mutex_enter(&ufs_ihash_lock);
vp = ufs_ihashlookup(ump->um_dev, blkp->bi_inode);
mutex_enter(&ulfs_ihash_lock);
vp = ulfs_ihashlookup(ump->um_dev, blkp->bi_inode);
if (vp != NULL && !(vp->v_iflag & VI_XLOCK)) {
ip = VTOI(vp);
mutex_enter(vp->v_interlock);
mutex_exit(&ufs_ihash_lock);
mutex_exit(&ulfs_ihash_lock);
if (lfs_vref(vp)) {
v_daddr = LFS_UNUSED_DADDR;
continue;
}
numrefed++;
} else {
mutex_exit(&ufs_ihash_lock);
mutex_exit(&ulfs_ihash_lock);
/*
* Don't VFS_VGET if we're being unmounted,
* since we hold vfs_busy().
@@ -760,6 +766,7 @@ lfs_bmapv(struct proc *p, fsid_t *fsidp, BLOCK_INFO *blkiov, int blkcnt)
continue;
} else {
KASSERT(VOP_ISLOCKED(vp));
VTOI(vp)->i_lfs_iflags |= LFSI_BMAP;
VOP_UNLOCK(vp);
numrefed++;
}
@@ -799,10 +806,10 @@ lfs_bmapv(struct proc *p, fsid_t *fsidp, BLOCK_INFO *blkiov, int blkcnt)
blkp->bi_daddr = LFS_UNUSED_DADDR;
continue;
}
blkp->bi_daddr = dbtofsb(fs, bi_daddr);
blkp->bi_daddr = LFS_DBTOFSB(fs, bi_daddr);
/* Fill in the block size, too */
if (blkp->bi_lbn >= 0)
blkp->bi_size = blksize(fs, ip, blkp->bi_lbn);
blkp->bi_size = lfs_blksize(fs, ip, blkp->bi_lbn);
else
blkp->bi_size = fs->lfs_bsize;
}
@@ -814,6 +821,9 @@ lfs_bmapv(struct proc *p, fsid_t *fsidp, BLOCK_INFO *blkiov, int blkcnt)
*/
if (v_daddr != LFS_UNUSED_DADDR) {
lfs_vunref(vp);
/* Recycle as above. */
if (ip->i_lfs_iflags & LFSI_BMAP)
vrecycle(vp, NULL);
numrefed--;
}
@@ -848,8 +858,9 @@ sys_lfs_segclean(struct lwp *l, const struct sys_lfs_segclean_args *uap, registe
int error;
unsigned long segnum;
if ((error = kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
NULL)) != 0)
error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_LFS,
KAUTH_REQ_SYSTEM_LFS_SEGCLEAN, NULL, NULL, NULL);
if (error)
return (error);
if ((error = copyin(SCARG(uap, fsidp), &fsid, sizeof(fsid_t))) != 0)
@@ -857,7 +868,7 @@ sys_lfs_segclean(struct lwp *l, const struct sys_lfs_segclean_args *uap, registe
if ((mntp = vfs_getvfs(&fsid)) == NULL)
return (ENOENT);
fs = VFSTOUFS(mntp)->um_lfs;
fs = VFSTOULFS(mntp)->um_lfs;
segnum = SCARG(uap, segment);
if ((error = vfs_busy(mntp, NULL)) != 0)
@@ -884,7 +895,7 @@ lfs_do_segclean(struct lfs *fs, unsigned long segnum)
CLEANERINFO *cip;
SEGUSE *sup;
if (dtosn(fs, fs->lfs_curseg) == segnum) {
if (lfs_dtosn(fs, fs->lfs_curseg) == segnum) {
return (EBUSY);
}
@@ -908,17 +919,17 @@ lfs_do_segclean(struct lfs *fs, unsigned long segnum)
return (EALREADY);
}
fs->lfs_avail += segtod(fs, 1);
fs->lfs_avail += lfs_segtod(fs, 1);
if (sup->su_flags & SEGUSE_SUPERBLOCK)
fs->lfs_avail -= btofsb(fs, LFS_SBPAD);
fs->lfs_avail -= lfs_btofsb(fs, LFS_SBPAD);
if (fs->lfs_version > 1 && segnum == 0 &&
fs->lfs_start < btofsb(fs, LFS_LABELPAD))
fs->lfs_avail -= btofsb(fs, LFS_LABELPAD) - fs->lfs_start;
fs->lfs_start < lfs_btofsb(fs, LFS_LABELPAD))
fs->lfs_avail -= lfs_btofsb(fs, LFS_LABELPAD) - fs->lfs_start;
mutex_enter(&lfs_lock);
fs->lfs_bfree += sup->su_nsums * btofsb(fs, fs->lfs_sumsize) +
btofsb(fs, sup->su_ninos * fs->lfs_ibsize);
fs->lfs_dmeta -= sup->su_nsums * btofsb(fs, fs->lfs_sumsize) +
btofsb(fs, sup->su_ninos * fs->lfs_ibsize);
fs->lfs_bfree += sup->su_nsums * lfs_btofsb(fs, fs->lfs_sumsize) +
lfs_btofsb(fs, sup->su_ninos * fs->lfs_ibsize);
fs->lfs_dmeta -= sup->su_nsums * lfs_btofsb(fs, fs->lfs_sumsize) +
lfs_btofsb(fs, sup->su_ninos * fs->lfs_ibsize);
if (fs->lfs_dmeta < 0)
fs->lfs_dmeta = 0;
mutex_exit(&lfs_lock);
@@ -959,7 +970,7 @@ lfs_segwait(fsid_t *fsidp, struct timeval *tv)
if (fsidp == NULL || (mntp = vfs_getvfs(fsidp)) == NULL)
addr = &lfs_allclean_wakeup;
else
addr = &VFSTOUFS(mntp)->um_lfs->lfs_nextseg;
addr = &VFSTOULFS(mntp)->um_lfs->lfs_nextseg;
/*
* XXX THIS COULD SLEEP FOREVER IF TIMEOUT IS {0,0}!
* XXX IS THAT WHAT IS INTENDED?
@@ -992,8 +1003,9 @@ sys___lfs_segwait50(struct lwp *l, const struct sys___lfs_segwait50_args *uap,
int error;
/* XXX need we be su to segwait? */
if ((error = kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
NULL)) != 0)
error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_LFS,
KAUTH_REQ_SYSTEM_LFS_SEGWAIT, NULL, NULL, NULL);
if (error)
return (error);
if ((error = copyin(SCARG(uap, fsidp), &fsid, sizeof(fsid_t))) != 0)
return (error);
@@ -1024,10 +1036,10 @@ lfs_fasthashget(dev_t dev, ino_t ino, struct vnode **vpp)
{
struct vnode *vp;
mutex_enter(&ufs_ihash_lock);
if ((vp = ufs_ihashlookup(dev, ino)) != NULL) {
mutex_enter(&ulfs_ihash_lock);
if ((vp = ulfs_ihashlookup(dev, ino)) != NULL) {
mutex_enter(vp->v_interlock);
mutex_exit(&ufs_ihash_lock);
mutex_exit(&ulfs_ihash_lock);
if (vp->v_iflag & VI_XLOCK) {
DLOG((DLOG_CLEAN, "lfs_fastvget: ino %d VI_XLOCK\n",
ino));
@@ -1042,7 +1054,7 @@ lfs_fasthashget(dev_t dev, ino_t ino, struct vnode **vpp)
return EAGAIN;
}
} else {
mutex_exit(&ufs_ihash_lock);
mutex_exit(&ulfs_ihash_lock);
}
*vpp = vp;
@@ -1051,18 +1063,18 @@ lfs_fasthashget(dev_t dev, ino_t ino, struct vnode **vpp)
int
lfs_fastvget(struct mount *mp, ino_t ino, daddr_t daddr, struct vnode **vpp,
struct ufs1_dinode *dinp)
struct ulfs1_dinode *dinp)
{
struct inode *ip;
struct ufs1_dinode *dip;
struct ulfs1_dinode *dip;
struct vnode *vp;
struct ufsmount *ump;
struct ulfsmount *ump;
dev_t dev;
int error, retries;
struct buf *bp;
struct lfs *fs;
ump = VFSTOUFS(mp);
ump = VFSTOULFS(mp);
dev = ump->um_dev;
fs = ump->um_lfs;
@@ -1103,10 +1115,10 @@ lfs_fastvget(struct mount *mp, ino_t ino, daddr_t daddr, struct vnode **vpp,
return (error);
}
mutex_enter(&ufs_hashlock);
mutex_enter(&ulfs_hashlock);
error = lfs_fasthashget(dev, ino, vpp);
if (error != 0 || *vpp != NULL) {
mutex_exit(&ufs_hashlock);
mutex_exit(&ulfs_hashlock);
ungetnewvnode(vp);
return (error);
}
@@ -1121,8 +1133,13 @@ lfs_fastvget(struct mount *mp, ino_t ino, daddr_t daddr, struct vnode **vpp,
* disk portion of this inode to be read.
*/
ip = VTOI(vp);
ufs_ihashins(ip);
mutex_exit(&ufs_hashlock);
ulfs_ihashins(ip);
mutex_exit(&ulfs_hashlock);
#ifdef notyet
/* Not found in the cache => this vnode was loaded only for cleaning. */
ip->i_lfs_iflags |= LFSI_BMAP;
#endif
/*
* XXX
@@ -1134,11 +1151,11 @@ lfs_fastvget(struct mount *mp, ino_t ino, daddr_t daddr, struct vnode **vpp,
/* Read in the disk contents for the inode, copy into the inode. */
if (dinp) {
error = copyin(dinp, ip->i_din.ffs1_din, sizeof (struct ufs1_dinode));
error = copyin(dinp, ip->i_din.ffs1_din, sizeof (struct ulfs1_dinode));
if (error) {
DLOG((DLOG_CLEAN, "lfs_fastvget: dinode copyin failed"
" for ino %d\n", ino));
ufs_ihashrem(ip);
ulfs_ihashrem(ip);
/* Unlock and discard unneeded inode. */
VOP_UNLOCK(vp);
@@ -1151,7 +1168,7 @@ lfs_fastvget(struct mount *mp, ino_t ino, daddr_t daddr, struct vnode **vpp,
} else {
retries = 0;
again:
error = bread(ump->um_devvp, fsbtodb(fs, daddr), fs->lfs_ibsize,
error = bread(ump->um_devvp, LFS_FSBTODB(fs, daddr), fs->lfs_ibsize,
NOCRED, 0, &bp);
if (error) {
DLOG((DLOG_CLEAN, "lfs_fastvget: bread failed (%d)\n",
@@ -1161,12 +1178,11 @@ lfs_fastvget(struct mount *mp, ino_t ino, daddr_t daddr, struct vnode **vpp,
* would be misleading to leave it on its hash chain.
* Iput() will return it to the free list.
*/
ufs_ihashrem(ip);
ulfs_ihashrem(ip);
/* Unlock and discard unneeded inode. */
VOP_UNLOCK(vp);
lfs_vunref(vp);
brelse(bp, 0);
*vpp = NULL;
return (error);
}
+430 -229
View File
File diff suppressed because it is too large Load Diff
+504 -327
View File
File diff suppressed because it is too large Load Diff
+411
View File
@@ -0,0 +1,411 @@
/* $NetBSD: ulfs_bmap.c,v 1.5 2013/07/28 01:10:49 dholland Exp $ */
/* from NetBSD: ufs_bmap.c,v 1.50 2013/01/22 09:39:18 dholland Exp */
/*
* Copyright (c) 1989, 1991, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* 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.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* @(#)ufs_bmap.c 8.8 (Berkeley) 8/11/95
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ulfs_bmap.c,v 1.5 2013/07/28 01:10:49 dholland Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/stat.h>
#include <sys/buf.h>
#include <sys/proc.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/resourcevar.h>
#include <sys/trace.h>
#include <sys/fstrans.h>
#include <miscfs/specfs/specdev.h>
#include <ufs/lfs/ulfs_inode.h>
#include <ufs/lfs/ulfsmount.h>
#include <ufs/lfs/ulfs_extern.h>
#include <ufs/lfs/ulfs_bswap.h>
static bool
ulfs_issequential(const struct lfs *fs, daddr_t daddr0, daddr_t daddr1)
{
/* for ulfs, blocks in a hole is not 'contiguous'. */
if (daddr0 == 0)
return false;
return (daddr0 + fs->um_seqinc == daddr1);
}
/*
* Bmap converts the logical block number of a file to its physical block
* number on the disk. The conversion is done by using the logical block
* number to index into the array of block pointers described by the dinode.
*/
int
ulfs_bmap(void *v)
{
struct vop_bmap_args /* {
struct vnode *a_vp;
daddr_t a_bn;
struct vnode **a_vpp;
daddr_t *a_bnp;
int *a_runp;
} */ *ap = v;
int error;
/*
* Check for underlying vnode requests and ensure that logical
* to physical mapping is requested.
*/
if (ap->a_vpp != NULL)
*ap->a_vpp = VTOI(ap->a_vp)->i_devvp;
if (ap->a_bnp == NULL)
return (0);
fstrans_start(ap->a_vp->v_mount, FSTRANS_SHARED);
error = ulfs_bmaparray(ap->a_vp, ap->a_bn, ap->a_bnp, NULL, NULL,
ap->a_runp, ulfs_issequential);
fstrans_done(ap->a_vp->v_mount);
return error;
}
/*
* Indirect blocks are now on the vnode for the file. They are given negative
* logical block numbers. Indirect blocks are addressed by the negative
* address of the first data block to which they point. Double indirect blocks
* are addressed by one less than the address of the first indirect block to
* which they point. Triple indirect blocks are addressed by one less than
* the address of the first double indirect block to which they point.
*
* ulfs_bmaparray does the bmap conversion, and if requested returns the
* array of logical blocks which must be traversed to get to a block.
* Each entry contains the offset into that block that gets you to the
* next block and the disk address of the block (if it is assigned).
*/
int
ulfs_bmaparray(struct vnode *vp, daddr_t bn, daddr_t *bnp, struct indir *ap,
int *nump, int *runp, ulfs_issequential_callback_t is_sequential)
{
struct inode *ip;
struct buf *bp, *cbp;
struct ulfsmount *ump;
struct lfs *fs;
struct mount *mp;
struct indir a[ULFS_NIADDR + 1], *xap;
daddr_t daddr;
daddr_t metalbn;
int error, maxrun = 0, num;
ip = VTOI(vp);
mp = vp->v_mount;
ump = ip->i_ump;
fs = ip->i_lfs;
#ifdef DIAGNOSTIC
if ((ap != NULL && nump == NULL) || (ap == NULL && nump != NULL))
panic("ulfs_bmaparray: invalid arguments");
#endif
if (runp) {
/*
* XXX
* If MAXBSIZE is the largest transfer the disks can handle,
* we probably want maxrun to be 1 block less so that we
* don't create a block larger than the device can handle.
*/
*runp = 0;
maxrun = MAXPHYS / mp->mnt_stat.f_iosize - 1;
}
if (bn >= 0 && bn < ULFS_NDADDR) {
if (nump != NULL)
*nump = 0;
if (ump->um_fstype == ULFS1)
daddr = ulfs_rw32(ip->i_ffs1_db[bn],
ULFS_MPNEEDSWAP(fs));
else
daddr = ulfs_rw64(ip->i_ffs2_db[bn],
ULFS_MPNEEDSWAP(fs));
*bnp = blkptrtodb(fs, daddr);
/*
* Since this is FFS independent code, we are out of
* scope for the definitions of BLK_NOCOPY and
* BLK_SNAP, but we do know that they will fall in
* the range 1..um_seqinc, so we use that test and
* return a request for a zeroed out buffer if attempts
* are made to read a BLK_NOCOPY or BLK_SNAP block.
*/
if ((ip->i_flags & (SF_SNAPSHOT | SF_SNAPINVAL)) == SF_SNAPSHOT
&& daddr > 0 &&
daddr < fs->um_seqinc) {
*bnp = -1;
} else if (*bnp == 0) {
if ((ip->i_flags & (SF_SNAPSHOT | SF_SNAPINVAL))
== SF_SNAPSHOT) {
*bnp = blkptrtodb(fs, bn * fs->um_seqinc);
} else {
*bnp = -1;
}
} else if (runp) {
if (ump->um_fstype == ULFS1) {
for (++bn; bn < ULFS_NDADDR && *runp < maxrun &&
is_sequential(fs,
ulfs_rw32(ip->i_ffs1_db[bn - 1],
ULFS_MPNEEDSWAP(fs)),
ulfs_rw32(ip->i_ffs1_db[bn],
ULFS_MPNEEDSWAP(fs)));
++bn, ++*runp);
} else {
for (++bn; bn < ULFS_NDADDR && *runp < maxrun &&
is_sequential(fs,
ulfs_rw64(ip->i_ffs2_db[bn - 1],
ULFS_MPNEEDSWAP(fs)),
ulfs_rw64(ip->i_ffs2_db[bn],
ULFS_MPNEEDSWAP(fs)));
++bn, ++*runp);
}
}
return (0);
}
xap = ap == NULL ? a : ap;
if (!nump)
nump = &num;
if ((error = ulfs_getlbns(vp, bn, xap, nump)) != 0)
return (error);
num = *nump;
/* Get disk address out of indirect block array */
if (ump->um_fstype == ULFS1)
daddr = ulfs_rw32(ip->i_ffs1_ib[xap->in_off],
ULFS_MPNEEDSWAP(fs));
else
daddr = ulfs_rw64(ip->i_ffs2_ib[xap->in_off],
ULFS_MPNEEDSWAP(fs));
for (bp = NULL, ++xap; --num; ++xap) {
/*
* Exit the loop if there is no disk address assigned yet and
* the indirect block isn't in the cache, or if we were
* looking for an indirect block and we've found it.
*/
metalbn = xap->in_lbn;
if (metalbn == bn)
break;
if (daddr == 0) {
mutex_enter(&bufcache_lock);
cbp = incore(vp, metalbn);
mutex_exit(&bufcache_lock);
if (cbp == NULL)
break;
}
/*
* If we get here, we've either got the block in the cache
* or we have a disk address for it, go fetch it.
*/
if (bp)
brelse(bp, 0);
xap->in_exists = 1;
bp = getblk(vp, metalbn, mp->mnt_stat.f_iosize, 0, 0);
if (bp == NULL) {
/*
* getblk() above returns NULL only iff we are
* pagedaemon. See the implementation of getblk
* for detail.
*/
return (ENOMEM);
}
if (bp->b_oflags & (BO_DONE | BO_DELWRI)) {
trace(TR_BREADHIT, pack(vp, size), metalbn);
}
#ifdef DIAGNOSTIC
else if (!daddr)
panic("ulfs_bmaparray: indirect block not in cache");
#endif
else {
trace(TR_BREADMISS, pack(vp, size), metalbn);
bp->b_blkno = blkptrtodb(fs, daddr);
bp->b_flags |= B_READ;
BIO_SETPRIO(bp, BPRIO_TIMECRITICAL);
VOP_STRATEGY(vp, bp);
curlwp->l_ru.ru_inblock++; /* XXX */
if ((error = biowait(bp)) != 0) {
brelse(bp, 0);
return (error);
}
}
if (ump->um_fstype == ULFS1) {
daddr = ulfs_rw32(((u_int32_t *)bp->b_data)[xap->in_off],
ULFS_MPNEEDSWAP(fs));
if (num == 1 && daddr && runp) {
for (bn = xap->in_off + 1;
bn < MNINDIR(fs) && *runp < maxrun &&
is_sequential(fs,
ulfs_rw32(((int32_t *)bp->b_data)[bn-1],
ULFS_MPNEEDSWAP(fs)),
ulfs_rw32(((int32_t *)bp->b_data)[bn],
ULFS_MPNEEDSWAP(fs)));
++bn, ++*runp);
}
} else {
daddr = ulfs_rw64(((u_int64_t *)bp->b_data)[xap->in_off],
ULFS_MPNEEDSWAP(fs));
if (num == 1 && daddr && runp) {
for (bn = xap->in_off + 1;
bn < MNINDIR(fs) && *runp < maxrun &&
is_sequential(fs,
ulfs_rw64(((int64_t *)bp->b_data)[bn-1],
ULFS_MPNEEDSWAP(fs)),
ulfs_rw64(((int64_t *)bp->b_data)[bn],
ULFS_MPNEEDSWAP(fs)));
++bn, ++*runp);
}
}
}
if (bp)
brelse(bp, 0);
/*
* Since this is FFS independent code, we are out of scope for the
* definitions of BLK_NOCOPY and BLK_SNAP, but we do know that they
* will fall in the range 1..um_seqinc, so we use that test and
* return a request for a zeroed out buffer if attempts are made
* to read a BLK_NOCOPY or BLK_SNAP block.
*/
if ((ip->i_flags & (SF_SNAPSHOT | SF_SNAPINVAL)) == SF_SNAPSHOT
&& daddr > 0 && daddr < fs->um_seqinc) {
*bnp = -1;
return (0);
}
*bnp = blkptrtodb(fs, daddr);
if (*bnp == 0) {
if ((ip->i_flags & (SF_SNAPSHOT | SF_SNAPINVAL))
== SF_SNAPSHOT) {
*bnp = blkptrtodb(fs, bn * fs->um_seqinc);
} else {
*bnp = -1;
}
}
return (0);
}
/*
* Create an array of logical block number/offset pairs which represent the
* path of indirect blocks required to access a data block. The first "pair"
* contains the logical block number of the appropriate single, double or
* triple indirect block and the offset into the inode indirect block array.
* Note, the logical block number of the inode single/double/triple indirect
* block appears twice in the array, once with the offset into the i_ffs1_ib and
* once with the offset into the page itself.
*/
int
ulfs_getlbns(struct vnode *vp, daddr_t bn, struct indir *ap, int *nump)
{
daddr_t metalbn, realbn;
struct ulfsmount *ump;
struct lfs *fs;
int64_t blockcnt;
int lbc;
int i, numlevels, off;
ump = VFSTOULFS(vp->v_mount);
fs = ump->um_lfs;
if (nump)
*nump = 0;
numlevels = 0;
realbn = bn;
if (bn < 0)
bn = -bn;
KASSERT(bn >= ULFS_NDADDR);
/*
* Determine the number of levels of indirection. After this loop
* is done, blockcnt indicates the number of data blocks possible
* at the given level of indirection, and ULFS_NIADDR - i is the number
* of levels of indirection needed to locate the requested block.
*/
bn -= ULFS_NDADDR;
for (lbc = 0, i = ULFS_NIADDR;; i--, bn -= blockcnt) {
if (i == 0)
return (EFBIG);
lbc += fs->um_lognindir;
blockcnt = (int64_t)1 << lbc;
if (bn < blockcnt)
break;
}
/* Calculate the address of the first meta-block. */
metalbn = -((realbn >= 0 ? realbn : -realbn) - bn + ULFS_NIADDR - i);
/*
* At each iteration, off is the offset into the bap array which is
* an array of disk addresses at the current level of indirection.
* The logical block number and the offset in that block are stored
* into the argument array.
*/
ap->in_lbn = metalbn;
ap->in_off = off = ULFS_NIADDR - i;
ap->in_exists = 0;
ap++;
for (++numlevels; i <= ULFS_NIADDR; i++) {
/* If searching for a meta-data block, quit when found. */
if (metalbn == realbn)
break;
lbc -= fs->um_lognindir;
off = (bn >> lbc) & (MNINDIR(fs) - 1);
++numlevels;
ap->in_lbn = metalbn;
ap->in_off = off;
ap->in_exists = 0;
++ap;
metalbn -= -1 + ((int64_t)off << lbc);
}
if (nump)
*nump = numlevels;
return (0);
}
+81
View File
@@ -0,0 +1,81 @@
/* $NetBSD: ulfs_bswap.h,v 1.6 2013/10/18 15:15:22 christos Exp $ */
/* from NetBSD: ufs_bswap.h,v 1.19 2009/10/19 18:41:17 bouyer Exp */
/*
* Copyright (c) 1998 Manuel Bouyer.
*
* 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 _UFS_LFS_ULFS_BSWAP_H_
#define _UFS_LFS_ULFS_BSWAP_H_
#if defined(_KERNEL_OPT)
#include "opt_lfs.h"
#endif
#include <sys/bswap.h>
/* Macros to access ULFS flags */
#ifdef LFS_EI
#define ULFS_MPNEEDSWAP(lfs) ((lfs)->um_flags & ULFS_NEEDSWAP)
#define ULFS_FSNEEDSWAP(fs) ((fs)->fs_flags & FS_SWAPPED)
#define ULFS_IPNEEDSWAP(ip) ULFS_MPNEEDSWAP((ip)->i_lfs)
#else
#define ULFS_MPNEEDSWAP(ump) (__USE(ump), 0)
#define ULFS_FSNEEDSWAP(fs) (__USE(fs), 0)
#define ULFS_IPNEEDSWAP(ip) (__USE(ip), 0)
#endif
#if !defined(_KERNEL) || defined(LFS_EI)
/* inlines for access to swapped data */
static inline u_int16_t
ulfs_rw16(uint16_t a, int ns)
{
return ((ns) ? bswap16(a) : (a));
}
static inline u_int32_t
ulfs_rw32(uint32_t a, int ns)
{
return ((ns) ? bswap32(a) : (a));
}
static inline u_int64_t
ulfs_rw64(uint64_t a, int ns)
{
return ((ns) ? bswap64(a) : (a));
}
#else
#define ulfs_rw16(a, ns) (__USE(ns), (uint16_t)(a))
#define ulfs_rw32(a, ns) (__USE(ns), (uint32_t)(a))
#define ulfs_rw64(a, ns) (__USE(ns), (uint64_t)(a))
#endif
#define ulfs_add16(a, b, ns) \
(a) = ulfs_rw16(ulfs_rw16((a), (ns)) + (b), (ns))
#define ulfs_add32(a, b, ns) \
(a) = ulfs_rw32(ulfs_rw32((a), (ns)) + (b), (ns))
#define ulfs_add64(a, b, ns) \
(a) = ulfs_rw64(ulfs_rw64((a), (ns)) + (b), (ns))
#endif /* !_UFS_LFS_ULFS_BSWAP_H_ */
+62
View File
@@ -0,0 +1,62 @@
/* $NetBSD: ulfs_dinode.h,v 1.11 2013/06/08 22:19:01 dholland Exp $ */
/* from NetBSD: dinode.h,v 1.22 2013/01/22 09:39:18 dholland Exp */
/*
* Copyright (c) 2002 Networks Associates Technology, Inc.
* All rights reserved.
*
* This software was developed for the FreeBSD Project by Marshall
* Kirk McKusick and Network Associates Laboratories, the Security
* Research Division of Network Associates, Inc. under DARPA/SPAWAR
* contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
* research program
*
* Copyright (c) 1982, 1989, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* 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.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* @(#)dinode.h 8.9 (Berkeley) 3/29/95
*/
#ifndef _UFS_LFS_ULFS_DINODE_H_
#define _UFS_LFS_ULFS_DINODE_H_
#include <ufs/lfs/lfs.h>
/* 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. */
#endif /* !_UFS_LFS_ULFS_DINODE_H_ */
File diff suppressed because it is too large Load Diff
+130
View File
@@ -0,0 +1,130 @@
/* $NetBSD: ulfs_dirhash.h,v 1.5 2013/06/08 02:14:46 dholland Exp $ */
/* from NetBSD: dirhash.h,v 1.6 2008/06/04 11:33:19 ad Exp */
/*
* Copyright (c) 2001 Ian Dowse. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD: src/sys/ufs/ufs/dirhash.h,v 1.2.2.2 2004/12/08 11:54:13 dwmalone Exp $
*/
#ifndef _UFS_LFS_ULFS_DIRHASH_H_
#define _UFS_LFS_ULFS_DIRHASH_H_
/*
* For fast operations on large directories, we maintain a hash
* that maps the file name to the offset of the directory entry within
* the directory file.
*
* The hashing uses a dumb spillover to the next free slot on
* collisions, so we must keep the utilisation low to avoid
* long linear searches. Deleted entries that are not the last
* in a chain must be marked DIRHASH_DEL.
*
* We also maintain information about free space in each block
* to speed up creations.
*/
#define DIRHASH_EMPTY (-1) /* entry unused */
#define DIRHASH_DEL (-2) /* deleted entry; may be part of chain */
#define DIRALIGN 4
#define DH_NFSTATS (LFS_DIRECTSIZ(LFS_MAXNAMLEN + 1) / DIRALIGN)
/* max DIRALIGN words in a directory entry */
/*
* Dirhash uses a score mechanism to achieve a hybrid between a
* least-recently-used and a least-often-used algorithm for entry
* recycling. The score is incremented when a directory is used, and
* decremented when the directory is a candidate for recycling. When
* the score reaches zero, the hash is recycled. Hashes are linked
* together on a TAILQ list, and hashes with higher scores filter
* towards the tail (most recently used) end of the list.
*
* New hash entries are given an inital score of DH_SCOREINIT and are
* placed at the most-recently-used end of the list. This helps a lot
* in the worst-case case scenario where every directory access is
* to a directory that is not hashed (i.e. the working set of hash
* candidates is much larger than the configured memry limit). In this
* case it limits the number of hash builds to 1/DH_SCOREINIT of the
* number of accesses.
*/
#define DH_SCOREINIT 8 /* initial dh_score when dirhash built */
#define DH_SCOREMAX 64 /* max dh_score value */
/*
* The main hash table has 2 levels. It is an array of pointers to
* blocks of DH_NBLKOFF offsets.
*/
#define DH_BLKOFFSHIFT 8
#define DH_NBLKOFF (1 << DH_BLKOFFSHIFT)
#define DH_BLKOFFMASK (DH_NBLKOFF - 1)
#define DH_ENTRY(dh, slot) \
((dh)->dh_hash[(slot) >> DH_BLKOFFSHIFT][(slot) & DH_BLKOFFMASK])
struct dirhash {
kmutex_t dh_lock; /* protects all fields except dh_list */
doff_t **dh_hash; /* the hash array (2-level) */
size_t dh_hashsz;
int dh_narrays; /* number of entries in dh_hash */
int dh_hlen; /* total slots in the 2-level hash array */
int dh_hused; /* entries in use */
u_int8_t *dh_blkfree; /* free DIRALIGN words in each dir block */
size_t dh_blkfreesz;
int dh_nblk; /* size of dh_blkfree array */
int dh_dirblks; /* number of DIRBLKSIZ blocks in dir */
int dh_firstfree[DH_NFSTATS + 1]; /* first blk with N words free */
int dh_seqopt; /* sequential access optimisation enabled */
doff_t dh_seqoff; /* sequential access optimisation offset */
int dh_score; /* access count for this dirhash */
int dh_onlist; /* true if on the ulfsdirhash_list chain */
/* Protected by ulfsdirhash_lock. */
TAILQ_ENTRY(dirhash) dh_list; /* chain of all dirhashes */
};
/*
* Dirhash functions.
*/
int ulfsdirhash_build(struct inode *);
doff_t ulfsdirhash_findfree(struct inode *, int, int *);
doff_t ulfsdirhash_enduseful(struct inode *);
int ulfsdirhash_lookup(struct inode *, const char *, int, doff_t *,
struct buf **, doff_t *);
void ulfsdirhash_newblk(struct inode *, doff_t);
void ulfsdirhash_add(struct inode *, struct lfs_direct *, doff_t);
void ulfsdirhash_remove(struct inode *, struct lfs_direct *, doff_t);
void ulfsdirhash_move(struct inode *, struct lfs_direct *, doff_t, doff_t);
void ulfsdirhash_dirtrunc(struct inode *, doff_t);
void ulfsdirhash_free(struct inode *);
void ulfsdirhash_checkblock(struct inode *, char *, doff_t);
void ulfsdirhash_init(void);
void ulfsdirhash_done(void);
#endif /* !_UFS_LFS_ULFS_DIRHASH_H_ */
File diff suppressed because it is too large Load Diff
+129
View File
@@ -0,0 +1,129 @@
/* $NetBSD: ulfs_extattr.h,v 1.2 2013/06/06 00:48:04 dholland Exp $ */
/* from NetBSD: extattr.h,v 1.10 2011/10/09 21:15:34 chs Exp */
/*-
* Copyright (c) 1999-2001 Robert N. M. Watson
* All rights reserved.
*
* This software was developed by Robert Watson for the TrustedBSD Project.
*
* 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD: src/sys/ufs/ufs/extattr.h,v 1.20 2005/01/31 08:16:45 imp Exp $
*/
/*
* Support for file system extended attributes on the ULFS1 file system.
* Developed by the TrustedBSD Project.
*/
#ifndef _UFS_LFS_ULFS_EXTATTR_H_
#define _UFS_LFS_ULFS_EXTATTR_H_
#define ULFS_EXTATTR_MAGIC 0x00b5d5ec
#define ULFS_EXTATTR_VERSION 0x00000003
#define ULFS_EXTATTR_FSROOTSUBDIR ".attribute"
#define ULFS_EXTATTR_SUBDIR_SYSTEM "system"
#define ULFS_EXTATTR_SUBDIR_USER "user"
#define ULFS_EXTATTR_MAXEXTATTRNAME 65 /* including null */
#define ULFS_EXTATTR_ATTR_FLAG_INUSE 0x00000001 /* attr has been set */
#define ULFS_EXTATTR_PERM_KERNEL 0x00000000
#define ULFS_EXTATTR_PERM_ROOT 0x00000001
#define ULFS_EXTATTR_PERM_OWNER 0x00000002
#define ULFS_EXTATTR_PERM_ANYONE 0x00000003
#define ULFS_EXTATTR_UEPM_INITIALIZED 0x00000001
#define ULFS_EXTATTR_UEPM_STARTED 0x00000002
#define ULFS_EXTATTR_CMD_START EXTATTR_CMD_START
#define ULFS_EXTATTR_CMD_STOP EXTATTR_CMD_STOP
#define ULFS_EXTATTR_CMD_ENABLE 0x00000003
#define ULFS_EXTATTR_CMD_DISABLE 0x00000004
struct ulfs_extattr_fileheader {
uint32_t uef_magic; /* magic number for sanity checking */
uint32_t uef_version; /* version of attribute file */
uint32_t uef_size; /* size of attributes, w/o header */
};
struct ulfs_extattr_header {
uint32_t ueh_flags; /* flags for attribute */
uint32_t ueh_len; /* local defined length; <= uef_size */
uint32_t ueh_i_gen; /* generation number for sanity */
/* data follows the header */
};
#ifdef _KERNEL
#ifdef MALLOC_DECLARE
MALLOC_DECLARE(M_EXTATTR);
#endif
struct vnode;
LIST_HEAD(ulfs_extattr_list_head, ulfs_extattr_list_entry);
struct ulfs_extattr_list_entry {
LIST_ENTRY(ulfs_extattr_list_entry) uele_entries;
struct ulfs_extattr_fileheader uele_fileheader;
int uele_attrnamespace;
char uele_attrname[ULFS_EXTATTR_MAXEXTATTRNAME];
struct vnode *uele_backing_vnode;
int uele_flags;
};
/* uele_flags */
#define UELE_F_NEEDSWAP 0x01 /* needs byte swap */
#define UELE_NEEDSWAP(uele) ((uele)->uele_flags & UELE_F_NEEDSWAP)
struct lock;
struct ulfs_extattr_per_mount {
kmutex_t uepm_lock;
struct ulfs_extattr_list_head uepm_list;
kauth_cred_t uepm_ucred;
int uepm_lockcnt;
int uepm_flags;
};
void ulfs_extattr_uepm_init(struct ulfs_extattr_per_mount *uepm);
void ulfs_extattr_uepm_destroy(struct ulfs_extattr_per_mount *uepm);
int ulfs_extattr_start(struct mount *mp, struct lwp *l);
int ulfs_extattr_autostart(struct mount *mp, struct lwp *l);
void ulfs_extattr_stop(struct mount *mp, struct lwp *l);
int ulfs_extattrctl(struct mount *mp, int cmd, struct vnode *filename,
int attrnamespace, const char *attrname);
struct vop_getextattr_args;
int ulfs_getextattr(struct vop_getextattr_args *ap);
struct vop_deleteextattr_args;
int ulfs_deleteextattr(struct vop_deleteextattr_args *ap);
struct vop_setextattr_args;
int ulfs_setextattr(struct vop_setextattr_args *ap);
struct vop_listextattr_args;
int ulfs_listextattr(struct vop_listextattr_args *ap);
void ulfs_extattr_vnode_inactive(struct vnode *vp, struct lwp *l);
void ulfs_extattr_init(void);
void ulfs_extattr_done(void);
#endif /* !_KERNEL */
#endif /* !_UFS_LFS_ULFS_EXTATTR_H_ */
+191
View File
@@ -0,0 +1,191 @@
/* $NetBSD: ulfs_extern.h,v 1.10 2013/07/28 01:22:55 dholland Exp $ */
/* from NetBSD: ufs_extern.h,v 1.72 2012/05/09 00:21:18 riastradh Exp */
/*-
* Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* @(#)ufs_extern.h 8.10 (Berkeley) 5/14/95
*/
#ifndef _UFS_LFS_ULFS_EXTERN_H_
#define _UFS_LFS_ULFS_EXTERN_H_
#include <sys/mutex.h>
struct buf;
struct componentname;
struct disklabel;
struct dquot;
struct fid;
struct flock;
struct indir;
struct inode;
struct mbuf;
struct mount;
struct nameidata;
struct lfs_direct;
struct lwp;
struct ulfs_args;
struct ulfs_lookup_results;
struct ulfs_ufid;
struct ulfsmount;
struct uio;
struct vattr;
struct vnode;
extern pool_cache_t ulfs_direct_cache; /* memory pool for lfs_directs */
__BEGIN_DECLS
#define ulfs_abortop genfs_abortop
int ulfs_access(void *);
int ulfs_advlock(void *);
int ulfs_bmap(void *);
int ulfs_close(void *);
int ulfs_create(void *);
int ulfs_getattr(void *);
int ulfs_inactive(void *);
#define ulfs_fcntl genfs_fcntl
#define ulfs_ioctl genfs_enoioctl
#define ulfs_islocked genfs_islocked
int ulfs_link(void *);
#define ulfs_lock genfs_lock
int ulfs_lookup(void *);
int ulfs_mkdir(void *);
int ulfs_mknod(void *);
#define ulfs_mmap genfs_mmap
#define ulfs_revoke genfs_revoke
int ulfs_open(void *);
int ulfs_pathconf(void *);
int ulfs_print(void *);
int ulfs_readdir(void *);
int ulfs_readlink(void *);
int ulfs_remove(void *);
int ulfs_rmdir(void *);
#define ulfs_seek genfs_seek
#define ulfs_poll genfs_poll
int ulfs_setattr(void *);
int ulfs_strategy(void *);
int ulfs_symlink(void *);
#define ulfs_unlock genfs_unlock
int ulfs_whiteout(void *);
int ulfsspec_close(void *);
int ulfsspec_read(void *);
int ulfsspec_write(void *);
int ulfsfifo_read(void *);
int ulfsfifo_write(void *);
int ulfsfifo_close(void *);
/* ulfs_bmap.c */
typedef bool (*ulfs_issequential_callback_t)(const struct lfs *,
daddr_t, daddr_t);
int ulfs_bmaparray(struct vnode *, daddr_t, daddr_t *, struct indir *,
int *, int *, ulfs_issequential_callback_t);
int ulfs_getlbns(struct vnode *, daddr_t, struct indir *, int *);
/* ulfs_ihash.c */
void ulfs_ihashinit(void);
void ulfs_ihashreinit(void);
void ulfs_ihashdone(void);
struct vnode *ulfs_ihashlookup(dev_t, ino_t);
struct vnode *ulfs_ihashget(dev_t, ino_t, int);
void ulfs_ihashins(struct inode *);
void ulfs_ihashrem(struct inode *);
/* ulfs_inode.c */
int ulfs_reclaim(struct vnode *);
int ulfs_balloc_range(struct vnode *, off_t, off_t, kauth_cred_t, int);
/* ulfs_lookup.c */
void ulfs_dirbad(struct inode *, doff_t, const char *);
int ulfs_dirbadentry(struct vnode *, struct lfs_direct *, int);
void ulfs_makedirentry(struct inode *, struct componentname *,
struct lfs_direct *);
int ulfs_direnter(struct vnode *, const struct ulfs_lookup_results *,
struct vnode *, struct lfs_direct *,
struct componentname *, struct buf *);
int ulfs_dirremove(struct vnode *, const struct ulfs_lookup_results *,
struct inode *, int, int);
int ulfs_dirrewrite(struct inode *, off_t,
struct inode *, ino_t, int, int, int);
int ulfs_dirempty(struct inode *, ino_t, kauth_cred_t);
int ulfs_checkpath(struct inode *, struct inode *, kauth_cred_t);
int ulfs_parentcheck(struct vnode *, struct vnode *, kauth_cred_t,
int *, struct vnode **);
int ulfs_blkatoff(struct vnode *, off_t, char **, struct buf **, bool);
/* ulfs_quota.c */
/*
* Flags to lfs_chkdq() and lfs_chkiq()
*/
#define FORCE 0x01 /* force usage changes independent of limits */
void ulfsquota_init(struct inode *);
void ulfsquota_free(struct inode *);
int lfs_chkdq(struct inode *, int64_t, kauth_cred_t, int);
int lfs_chkiq(struct inode *, int32_t, kauth_cred_t, int);
int lfsquota_handle_cmd(struct mount *, struct lwp *,
struct quotactl_args *);
int lfs_qsync(struct mount *);
/* ulfs_quota1.c */
int lfsquota1_umount(struct mount *, int);
/* ulfs_quota2.c */
int lfsquota2_umount(struct mount *, int);
int lfs_quota2_mount(struct mount *);
/* ulfs_vfsops.c */
void ulfs_init(void);
void ulfs_reinit(void);
void ulfs_done(void);
int ulfs_start(struct mount *, int);
int ulfs_root(struct mount *, struct vnode **);
int ulfs_quotactl(struct mount *, struct quotactl_args *);
int ulfs_fhtovp(struct mount *, struct ulfs_ufid *, struct vnode **);
/* ulfs_vnops.c */
void ulfs_vinit(struct mount *, int (**)(void *),
int (**)(void *), struct vnode **);
int ulfs_makeinode(int, struct vnode *, const struct ulfs_lookup_results *,
struct vnode **, struct componentname *);
int ulfs_gop_alloc(struct vnode *, off_t, off_t, int, kauth_cred_t);
void ulfs_gop_markupdate(struct vnode *, int);
/*
* Snapshot function prototypes.
*/
void ulfs_snapgone(struct inode *);
__END_DECLS
extern kmutex_t ulfs_ihash_lock;
extern kmutex_t ulfs_hashlock;
#endif /* !_UFS_LFS_ULFS_EXTERN_H_ */
+192
View File
@@ -0,0 +1,192 @@
/* $NetBSD: ulfs_ihash.c,v 1.3 2013/06/06 00:48:04 dholland Exp $ */
/* from NetBSD: ufs_ihash.c,v 1.31 2011/06/12 03:36:02 rmind Exp */
/*
* Copyright (c) 1982, 1986, 1989, 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* @(#)ufs_ihash.c 8.7 (Berkeley) 5/17/95
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ulfs_ihash.c,v 1.3 2013/06/06 00:48:04 dholland Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/vnode.h>
#include <sys/proc.h>
#include <sys/mutex.h>
#include <ufs/lfs/ulfs_inode.h>
#include <ufs/lfs/ulfs_extern.h>
/*
* Structures associated with inode cacheing.
*/
static LIST_HEAD(ihashhead, inode) *ihashtbl;
static u_long ihash; /* size of hash table - 1 */
#define INOHASH(device, inum) (((device) + (inum)) & ihash)
kmutex_t ulfs_ihash_lock;
kmutex_t ulfs_hashlock;
/*
* Initialize inode hash table.
*/
void
ulfs_ihashinit(void)
{
mutex_init(&ulfs_hashlock, MUTEX_DEFAULT, IPL_NONE);
mutex_init(&ulfs_ihash_lock, MUTEX_DEFAULT, IPL_NONE);
ihashtbl = hashinit(desiredvnodes, HASH_LIST, true, &ihash);
}
/*
* Reinitialize inode hash table.
*/
void
ulfs_ihashreinit(void)
{
struct inode *ip;
struct ihashhead *oldhash, *hash;
u_long oldmask, mask, val;
int i;
hash = hashinit(desiredvnodes, HASH_LIST, true, &mask);
mutex_enter(&ulfs_ihash_lock);
oldhash = ihashtbl;
oldmask = ihash;
ihashtbl = hash;
ihash = mask;
for (i = 0; i <= oldmask; i++) {
while ((ip = LIST_FIRST(&oldhash[i])) != NULL) {
LIST_REMOVE(ip, i_hash);
val = INOHASH(ip->i_dev, ip->i_number);
LIST_INSERT_HEAD(&hash[val], ip, i_hash);
}
}
mutex_exit(&ulfs_ihash_lock);
hashdone(oldhash, HASH_LIST, oldmask);
}
/*
* Free inode hash table.
*/
void
ulfs_ihashdone(void)
{
hashdone(ihashtbl, HASH_LIST, ihash);
mutex_destroy(&ulfs_hashlock);
mutex_destroy(&ulfs_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 *
ulfs_ihashlookup(dev_t dev, ino_t inum)
{
struct inode *ip;
struct ihashhead *ipp;
KASSERT(mutex_owned(&ulfs_ihash_lock));
ipp = &ihashtbl[INOHASH(dev, inum)];
LIST_FOREACH(ip, ipp, i_hash) {
if (inum == ip->i_number && dev == ip->i_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 *
ulfs_ihashget(dev_t dev, ino_t inum, int flags)
{
struct ihashhead *ipp;
struct inode *ip;
struct vnode *vp;
loop:
mutex_enter(&ulfs_ihash_lock);
ipp = &ihashtbl[INOHASH(dev, inum)];
LIST_FOREACH(ip, ipp, i_hash) {
if (inum == ip->i_number && dev == ip->i_dev) {
vp = ITOV(ip);
if (flags == 0) {
mutex_exit(&ulfs_ihash_lock);
} else {
mutex_enter(vp->v_interlock);
mutex_exit(&ulfs_ihash_lock);
if (vget(vp, flags))
goto loop;
}
return (vp);
}
}
mutex_exit(&ulfs_ihash_lock);
return (NULL);
}
/*
* Insert the inode into the hash table, and return it locked.
*/
void
ulfs_ihashins(struct inode *ip)
{
struct ihashhead *ipp;
KASSERT(mutex_owned(&ulfs_hashlock));
/* lock the inode, then put it on the appropriate hash list */
VOP_LOCK(ITOV(ip), LK_EXCLUSIVE);
mutex_enter(&ulfs_ihash_lock);
ipp = &ihashtbl[INOHASH(ip->i_dev, ip->i_number)];
LIST_INSERT_HEAD(ipp, ip, i_hash);
mutex_exit(&ulfs_ihash_lock);
}
/*
* Remove the inode from the hash table.
*/
void
ulfs_ihashrem(struct inode *ip)
{
mutex_enter(&ulfs_ihash_lock);
LIST_REMOVE(ip, i_hash);
mutex_exit(&ulfs_ihash_lock);
}
+270
View File
@@ -0,0 +1,270 @@
/* $NetBSD: ulfs_inode.c,v 1.9 2013/07/28 00:37:07 dholland Exp $ */
/* from NetBSD: ufs_inode.c,v 1.89 2013/01/22 09:39:18 dholland Exp */
/*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* 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.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* @(#)ufs_inode.c 8.9 (Berkeley) 5/14/95
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ulfs_inode.c,v 1.9 2013/07/28 00:37:07 dholland Exp $");
#if defined(_KERNEL_OPT)
#include "opt_lfs.h"
#include "opt_quota.h"
#include "opt_wapbl.h"
#endif
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/kernel.h>
#include <sys/namei.h>
#include <sys/kauth.h>
#include <sys/wapbl.h>
#include <sys/fstrans.h>
#include <sys/kmem.h>
#include <ufs/lfs/lfs_extern.h>
#include <ufs/lfs/ulfs_inode.h>
#include <ufs/lfs/ulfsmount.h>
#include <ufs/lfs/ulfs_extern.h>
#ifdef LFS_DIRHASH
#include <ufs/lfs/ulfs_dirhash.h>
#endif
#ifdef LFS_EXTATTR
#include <ufs/lfs/ulfs_extattr.h>
#endif
#include <uvm/uvm.h>
extern int prtactive;
/*
* Last reference to an inode. If necessary, write or delete it.
*/
int
ulfs_inactive(void *v)
{
struct vop_inactive_args /* {
struct vnode *a_vp;
struct bool *a_recycle;
} */ *ap = v;
struct vnode *vp = ap->a_vp;
struct inode *ip = VTOI(vp);
struct mount *transmp;
mode_t mode;
int error = 0;
transmp = vp->v_mount;
fstrans_start(transmp, FSTRANS_LAZY);
/*
* Ignore inodes related to stale file handles.
*/
if (ip->i_mode == 0)
goto out;
if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
#ifdef LFS_EXTATTR
ulfs_extattr_vnode_inactive(vp, curlwp);
#endif
if (ip->i_size != 0) {
error = lfs_truncate(vp, (off_t)0, 0, NOCRED);
}
#if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
(void)lfs_chkiq(ip, -1, NOCRED, 0);
#endif
DIP_ASSIGN(ip, rdev, 0);
mode = ip->i_mode;
ip->i_mode = 0;
ip->i_omode = mode;
DIP_ASSIGN(ip, mode, 0);
ip->i_flag |= IN_CHANGE | IN_UPDATE;
/*
* Defer final inode free and update to ulfs_reclaim().
*/
}
if (ip->i_flag & (IN_CHANGE | IN_UPDATE | IN_MODIFIED)) {
lfs_update(vp, NULL, NULL, 0);
}
out:
/*
* If we are done with the inode, reclaim it
* so that it can be reused immediately.
*/
*ap->a_recycle = (ip->i_mode == 0);
VOP_UNLOCK(vp);
fstrans_done(transmp);
return (error);
}
/*
* Reclaim an inode so that it can be used for other purposes.
*/
int
ulfs_reclaim(struct vnode *vp)
{
struct inode *ip = VTOI(vp);
if (prtactive && vp->v_usecount > 1)
vprint("ulfs_reclaim: pushing active", vp);
/* XXX: do we really need two of these? */
/* note: originally the first was inside a wapbl txn */
lfs_update(vp, NULL, NULL, UPDATE_CLOSE);
lfs_update(vp, NULL, NULL, UPDATE_CLOSE);
/*
* Remove the inode from its hash chain.
*/
ulfs_ihashrem(ip);
if (ip->i_devvp) {
vrele(ip->i_devvp);
ip->i_devvp = 0;
}
#if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
ulfsquota_free(ip);
#endif
#ifdef LFS_DIRHASH
if (ip->i_dirhash != NULL)
ulfsdirhash_free(ip);
#endif
return (0);
}
/*
* allocate a range of blocks in a file.
* after this function returns, any page entirely contained within the range
* will map to invalid data and thus must be overwritten before it is made
* accessible to others.
*/
int
ulfs_balloc_range(struct vnode *vp, off_t off, off_t len, kauth_cred_t cred,
int flags)
{
off_t neweof; /* file size after the operation */
off_t neweob; /* offset next to the last block after the operation */
off_t pagestart; /* starting offset of range covered by pgs */
off_t eob; /* offset next to allocated blocks */
struct uvm_object *uobj;
int i, delta, error, npages;
int bshift = vp->v_mount->mnt_fs_bshift;
int bsize = 1 << bshift;
int ppb = MAX(bsize >> PAGE_SHIFT, 1);
struct vm_page **pgs;
size_t pgssize;
UVMHIST_FUNC("ulfs_balloc_range"); UVMHIST_CALLED(ubchist);
UVMHIST_LOG(ubchist, "vp %p off 0x%x len 0x%x u_size 0x%x",
vp, off, len, vp->v_size);
neweof = MAX(vp->v_size, off + len);
GOP_SIZE(vp, neweof, &neweob, 0);
error = 0;
uobj = &vp->v_uobj;
/*
* read or create pages covering the range of the allocation and
* keep them locked until the new block is allocated, so there
* will be no window where the old contents of the new block are
* visible to racing threads.
*/
pagestart = trunc_page(off) & ~(bsize - 1);
npages = MIN(ppb, (round_page(neweob) - pagestart) >> PAGE_SHIFT);
pgssize = npages * sizeof(struct vm_page *);
pgs = kmem_zalloc(pgssize, KM_SLEEP);
/*
* adjust off to be block-aligned.
*/
delta = off & (bsize - 1);
off -= delta;
len += delta;
genfs_node_wrlock(vp);
mutex_enter(uobj->vmobjlock);
error = VOP_GETPAGES(vp, pagestart, pgs, &npages, 0,
VM_PROT_WRITE, 0, PGO_SYNCIO | PGO_PASTEOF | PGO_NOBLOCKALLOC |
PGO_NOTIMESTAMP | PGO_GLOCKHELD);
if (error) {
goto out;
}
/*
* now allocate the range.
*/
error = GOP_ALLOC(vp, off, len, flags, cred);
genfs_node_unlock(vp);
/*
* if the allocation succeeded, clear PG_CLEAN on all the pages
* and clear PG_RDONLY on any pages that are now fully backed
* by disk blocks. if the allocation failed, we do not invalidate
* the pages since they might have already existed and been dirty,
* in which case we need to keep them around. if we created the pages,
* they will be clean and read-only, and leaving such pages
* in the cache won't cause any problems.
*/
GOP_SIZE(vp, off + len, &eob, 0);
mutex_enter(uobj->vmobjlock);
mutex_enter(&uvm_pageqlock);
for (i = 0; i < npages; i++) {
KASSERT((pgs[i]->flags & PG_RELEASED) == 0);
if (!error) {
if (off <= pagestart + (i << PAGE_SHIFT) &&
pagestart + ((i + 1) << PAGE_SHIFT) <= eob) {
pgs[i]->flags &= ~PG_RDONLY;
}
pgs[i]->flags &= ~PG_CLEAN;
}
uvm_pageactivate(pgs[i]);
}
mutex_exit(&uvm_pageqlock);
uvm_page_unbusy(pgs, npages);
mutex_exit(uobj->vmobjlock);
out:
kmem_free(pgs, pgssize);
return error;
}
+278
View File
@@ -0,0 +1,278 @@
/* $NetBSD: ulfs_inode.h,v 1.10 2013/07/20 19:59:31 dholland Exp $ */
/* from NetBSD: inode.h,v 1.64 2012/11/19 00:36:21 jakllsch Exp */
/*
* Copyright (c) 1982, 1989, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* 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.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* @(#)inode.h 8.9 (Berkeley) 5/14/95
*/
#ifndef _UFS_LFS_ULFS_INODE_H_
#define _UFS_LFS_ULFS_INODE_H_
#include <sys/vnode.h>
#include <ufs/lfs/lfs_inode.h>
#include <ufs/lfs/ulfs_dinode.h>
#include <ufs/lfs/ulfs_quotacommon.h>
/*
* These macros are used to bracket ULFS directory ops, so that we can
* identify all the pages touched during directory ops which need to
* be ordered and flushed atomically, so that they may be recovered.
*
* Because we have to mark nodes VU_DIROP in order to prevent
* the cache from reclaiming them while a dirop is in progress, we must
* also manage the number of nodes so marked (otherwise we can run out).
* We do this by setting lfs_dirvcount to the number of marked vnodes; it
* is decremented during segment write, when VU_DIROP is taken off.
*/
#define MARK_VNODE(vp) lfs_mark_vnode(vp)
#define UNMARK_VNODE(vp) lfs_unmark_vnode(vp)
#define SET_DIROP_CREATE(dvp, vpp) lfs_set_dirop_create((dvp), (vpp))
#define SET_DIROP_REMOVE(dvp, vp) lfs_set_dirop((dvp), (vp))
int lfs_set_dirop_create(struct vnode *, struct vnode **);
int lfs_set_dirop(struct vnode *, struct vnode *);
#define SET_ENDOP_BASE(fs, dvp, str) \
do { \
mutex_enter(&lfs_lock); \
--(fs)->lfs_dirops; \
if (!(fs)->lfs_dirops) { \
if ((fs)->lfs_nadirop) { \
panic("SET_ENDOP: %s: no dirops but " \
" nadirop=%d", (str), \
(fs)->lfs_nadirop); \
} \
wakeup(&(fs)->lfs_writer); \
mutex_exit(&lfs_lock); \
lfs_check((dvp), LFS_UNUSED_LBN, 0); \
} else \
mutex_exit(&lfs_lock); \
} while(0)
#define SET_ENDOP_CREATE(fs, dvp, nvpp, str) \
do { \
UNMARK_VNODE(dvp); \
if (nvpp && *nvpp) \
UNMARK_VNODE(*nvpp); \
/* Check for error return to stem vnode leakage */ \
if (nvpp && *nvpp && !((*nvpp)->v_uflag & VU_DIROP)) \
ungetnewvnode(*(nvpp)); \
SET_ENDOP_BASE((fs), (dvp), (str)); \
lfs_reserve((fs), (dvp), NULL, -LFS_NRESERVE(fs)); \
vrele(dvp); \
} while(0)
#define SET_ENDOP_CREATE_AP(ap, str) \
SET_ENDOP_CREATE(VTOI((ap)->a_dvp)->i_lfs, (ap)->a_dvp, \
(ap)->a_vpp, (str))
#define SET_ENDOP_REMOVE(fs, dvp, ovp, str) \
do { \
UNMARK_VNODE(dvp); \
if (ovp) \
UNMARK_VNODE(ovp); \
SET_ENDOP_BASE((fs), (dvp), (str)); \
lfs_reserve((fs), (dvp), (ovp), -LFS_NRESERVE(fs)); \
vrele(dvp); \
if (ovp) \
vrele(ovp); \
} while(0)
/* Misc. definitions */
#define BW_CLEAN 1 /* Flag for lfs_bwrite_ext() */
#define PG_DELWRI PG_PAGER1 /* Local def for delayed pageout */
/* Resource limits */
#define LFS_MAX_RESOURCE(x, u) (((x) >> 2) - 10 * (u))
#define LFS_WAIT_RESOURCE(x, u) (((x) >> 1) - ((x) >> 3) - 10 * (u))
#define LFS_INVERSE_MAX_RESOURCE(x, u) (((x) + 10 * (u)) << 2)
#define LFS_MAX_BUFS LFS_MAX_RESOURCE(nbuf, 1)
#define LFS_WAIT_BUFS LFS_WAIT_RESOURCE(nbuf, 1)
#define LFS_INVERSE_MAX_BUFS(n) LFS_INVERSE_MAX_RESOURCE(n, 1)
#define LFS_MAX_BYTES LFS_MAX_RESOURCE(bufmem_lowater, PAGE_SIZE)
#define LFS_INVERSE_MAX_BYTES(n) LFS_INVERSE_MAX_RESOURCE(n, PAGE_SIZE)
#define LFS_WAIT_BYTES LFS_WAIT_RESOURCE(bufmem_lowater, PAGE_SIZE)
#define LFS_MAX_DIROP ((desiredvnodes >> 2) + (desiredvnodes >> 3))
#define SIZEOF_DIROP(fs) (2 * ((fs)->lfs_bsize + LFS_DINODE1_SIZE))
#define LFS_MAX_FSDIROP(fs) \
((fs)->lfs_nclean <= (fs)->lfs_resvseg ? 0 : \
(((fs)->lfs_nclean - (fs)->lfs_resvseg) * (fs)->lfs_ssize) / \
(2 * SIZEOF_DIROP(fs)))
#define LFS_MAX_PAGES lfs_max_pages()
#define LFS_WAIT_PAGES lfs_wait_pages()
#define LFS_BUFWAIT 2 /* How long to wait if over *_WAIT_* */
#ifdef _KERNEL
extern u_long bufmem_lowater, bufmem_hiwater; /* XXX */
int lfs_wait_pages(void);
int lfs_max_pages(void);
#endif /* _KERNEL */
/* How starved can we be before we start holding back page writes */
#define LFS_STARVED_FOR_SEGS(fs) ((fs)->lfs_nclean < (fs)->lfs_resvseg)
/*
* Reserved blocks for lfs_malloc
*/
/* Structure to keep reserved blocks */
typedef struct lfs_res_blk {
void *p;
LIST_ENTRY(lfs_res_blk) res;
int size;
char inuse;
} res_t;
/* Types for lfs_newbuf and lfs_malloc */
#define LFS_NB_UNKNOWN -1
#define LFS_NB_SUMMARY 0
#define LFS_NB_SBLOCK 1
#define LFS_NB_IBLOCK 2
#define LFS_NB_CLUSTER 3
#define LFS_NB_CLEAN 4
#define LFS_NB_BLKIOV 5
#define LFS_NB_COUNT 6 /* always last */
/* Number of reserved memory blocks of each type */
#define LFS_N_SUMMARIES 2
#define LFS_N_SBLOCKS 1 /* Always 1, to throttle superblock writes */
#define LFS_N_IBLOCKS 16 /* In theory ssize/bsize; in practice around 2 */
#define LFS_N_CLUSTERS 16 /* In theory ssize/MAXPHYS */
#define LFS_N_CLEAN 0
#define LFS_N_BLKIOV 1
/* Total count of "large" (non-pool) types */
#define LFS_N_TOTAL (LFS_N_SUMMARIES + LFS_N_SBLOCKS + LFS_N_IBLOCKS + \
LFS_N_CLUSTERS + LFS_N_CLEAN + LFS_N_BLKIOV)
/* Counts for pool types */
#define LFS_N_CL LFS_N_CLUSTERS
#define LFS_N_BPP 2
#define LFS_N_SEG 2
/*
* "struct buf" associated definitions
*/
/* Determine if a buffer belongs to the ifile */
#define IS_IFILE(bp) (VTOI(bp->b_vp)->i_number == LFS_IFILE_INUM)
#ifdef _KERNEL
/* This overlays the fid structure (see fstypes.h). */
struct ulfs_ufid {
u_int16_t ufid_len; /* Length of structure. */
u_int16_t ufid_pad; /* Force 32-bit alignment. */
u_int32_t ufid_ino; /* File number (ino). */
int32_t ufid_gen; /* Generation number. */
};
/* Filehandle structure for exported LFSes */
struct lfid {
struct ulfs_ufid lfid_ufid;
#define lfid_len lfid_ufid.ufid_len
#define lfid_ino lfid_ufid.ufid_ino
#define lfid_gen lfid_ufid.ufid_gen
uint32_t lfid_ident;
};
#endif /* _KERNEL */
/* Address calculations for metadata located in the inode */
#define S_INDIR(fs) -ULFS_NDADDR
#define D_INDIR(fs) (S_INDIR(fs) - LFS_NINDIR(fs) - 1)
#define T_INDIR(fs) (D_INDIR(fs) - LFS_NINDIR(fs) * LFS_NINDIR(fs) - 1)
/*
* "struct vnode" associated definitions
*/
/* Heuristic emptiness measure */
#define VPISEMPTY(vp) (LIST_EMPTY(&(vp)->v_dirtyblkhd) && \
!(vp->v_type == VREG && (vp)->v_iflag & VI_ONWORKLST) &&\
VTOI(vp)->i_lfs_nbtree == 0)
#define WRITEINPROG(vp) ((vp)->v_numoutput > 0 || \
(!LIST_EMPTY(&(vp)->v_dirtyblkhd) && \
!(VTOI(vp)->i_flag & (IN_MODIFIED | IN_ACCESSED | IN_CLEANING))))
#if defined(_KERNEL)
/*
* The DIP macro is used to access fields in the dinode that are
* not cached in the inode itself.
*/
#define DIP(ip, field) \
(((ip)->i_ump->um_fstype == ULFS1) ? \
(ip)->i_ffs1_##field : (ip)->i_ffs2_##field)
#define DIP_ASSIGN(ip, field, value) \
do { \
if ((ip)->i_ump->um_fstype == ULFS1) \
(ip)->i_ffs1_##field = (value); \
else \
(ip)->i_ffs2_##field = (value); \
} while(0)
#define DIP_ADD(ip, field, value) \
do { \
if ((ip)->i_ump->um_fstype == ULFS1) \
(ip)->i_ffs1_##field += (value); \
else \
(ip)->i_ffs2_##field += (value); \
} while(0)
#define SHORTLINK(ip) \
(((ip)->i_ump->um_fstype == ULFS1) ? \
(void *)(ip)->i_ffs1_db : (void *)(ip)->i_ffs2_db)
/*
* Structure used to pass around logical block paths generated by
* ulfs_getlbns and used by truncate and bmap code.
*/
struct indir {
daddr_t in_lbn; /* Logical block number. */
int in_off; /* Offset in buffer. */
int in_exists; /* Flag if the block exists. */
};
/* Convert between inode pointers and vnode pointers. */
#define VTOI(vp) ((struct inode *)(vp)->v_data)
#define ITOV(ip) ((ip)->i_vnode)
#endif /* _KERNEL */
#endif /* !_UFS_LFS_ULFS_INODE_H_ */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+146
View File
@@ -0,0 +1,146 @@
/* $NetBSD: ulfs_quota.h,v 1.4 2013/06/06 00:49:28 dholland Exp $ */
/* from NetBSD: ufs_quota.h,v 1.21 2012/02/18 06:13:23 matt Exp */
/*
* Copyright (c) 1982, 1986, 1990, 1993, 1995
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Robert Elz at The University of Melbourne.
*
* 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.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95
*/
#include <ufs/lfs/ulfs_quota1.h>
#include <ufs/lfs/ulfs_quota2.h>
struct quotakcursor; /* from <sys/quotactl.h> */
/* link to this quota in the quota inode (for QUOTA2) */
struct dq2_desc {
uint64_t dq2_lblkno; /* logical disk block holding this quota */
u_int dq2_blkoff; /* offset in disk block holding this quota */
};
/*
* The following structure records disk usage for a user or group on a
* filesystem. There is one allocated for each quota that exists on any
* filesystem for the current user or group. A cache is kept of recently
* used entries.
* Field markings and the corresponding locks:
* h: dqlock
* d: dq_interlock
*
* Lock order is: dq_interlock -> dqlock
* dq_interlock -> dqvp
*/
struct dquot {
LIST_ENTRY(dquot) dq_hash; /* h: hash list */
u_int16_t dq_flags; /* d: flags, see below */
u_int16_t dq_type; /* d: quota type of this dquot */
u_int32_t dq_cnt; /* h: count of active references */
u_int32_t dq_id; /* d: identifier this applies to */
struct ulfsmount *dq_ump; /* d: filesystem this is taken from */
kmutex_t dq_interlock; /* d: lock this dquot */
union {
struct dqblk dq1_dqb; /* d: actual usage & quotas */
struct dq2_desc dq2_desc; /* d: pointer to quota data */
} dq_un;
};
/*
* Flag values.
*/
#define DQ_MOD 0x04 /* this quota modified since read */
#define DQ_FAKE 0x08 /* no limits here, just usage */
#define DQ_WARN(ltype) (0x10 << ltype) /* has been warned about "type" limit */
/*
* Shorthand notation.
*/
#define dq_bhardlimit dq_un.dq1_dqb.dqb_bhardlimit
#define dq_bsoftlimit dq_un.dq1_dqb.dqb_bsoftlimit
#define dq_curblocks dq_un.dq1_dqb.dqb_curblocks
#define dq_ihardlimit dq_un.dq1_dqb.dqb_ihardlimit
#define dq_isoftlimit dq_un.dq1_dqb.dqb_isoftlimit
#define dq_curinodes dq_un.dq1_dqb.dqb_curinodes
#define dq_btime dq_un.dq1_dqb.dqb_btime
#define dq_itime dq_un.dq1_dqb.dqb_itime
#define dq2_lblkno dq_un.dq2_desc.dq2_lblkno
#define dq2_blkoff dq_un.dq2_desc.dq2_blkoff
/*
* If the system has never checked for a quota for this file, then it is
* set to NODQUOT. Once a write attempt is made the inode pointer is set
* to reference a dquot structure.
*/
#define NODQUOT NULL
extern kmutex_t lfs_dqlock;
extern kcondvar_t lfs_dqcv;
/*
* Quota name to error message mapping.
*/
extern const char *lfs_quotatypes[ULFS_MAXQUOTAS];
int lfs_getinoquota(struct inode *);
int lfs_dqget(struct vnode *, u_long, struct ulfsmount *, int, struct dquot **);
void lfs_dqref(struct dquot *);
void lfs_dqrele(struct vnode *, struct dquot *);
void lfs_dqflush(struct vnode *);
int lfs_chkdq1(struct inode *, int64_t, kauth_cred_t, int);
int lfs_chkiq1(struct inode *, int32_t, kauth_cred_t, int);
int lfs_q1sync(struct mount *);
int lfs_dq1get(struct vnode *, u_long, struct ulfsmount *, int, struct dquot *);
int lfs_dq1sync(struct vnode *, struct dquot *);
int lfsquota1_handle_cmd_get(struct ulfsmount *, const struct quotakey *,
struct quotaval *);
int lfsquota1_handle_cmd_put(struct ulfsmount *, const struct quotakey *,
const struct quotaval *);
int lfsquota1_handle_cmd_quotaon(struct lwp *, struct ulfsmount *, int,
const char *);
int lfsquota1_handle_cmd_quotaoff(struct lwp *, struct ulfsmount *, int);
int lfs_chkdq2(struct inode *, int64_t, kauth_cred_t, int);
int lfs_chkiq2(struct inode *, int32_t, kauth_cred_t, int);
int lfsquota2_handle_cmd_get(struct ulfsmount *, const struct quotakey *,
struct quotaval *);
int lfsquota2_handle_cmd_put(struct ulfsmount *, const struct quotakey *,
const struct quotaval *);
int lfsquota2_handle_cmd_delete(struct ulfsmount *, const struct quotakey *);
int lfsquota2_handle_cmd_cursorget(struct ulfsmount *, struct quotakcursor *,
struct quotakey *, struct quotaval *, unsigned, unsigned *);
int lfsquota2_handle_cmd_cursoropen(struct ulfsmount *, struct quotakcursor *);
int lfsquota2_handle_cmd_cursorclose(struct ulfsmount *, struct quotakcursor *);
int lfsquota2_handle_cmd_cursorskipidtype(struct ulfsmount *, struct quotakcursor *,
int);
int lfsquota2_handle_cmd_cursoratend(struct ulfsmount *, struct quotakcursor *,
int *);
int lfsquota2_handle_cmd_cursorrewind(struct ulfsmount *, struct quotakcursor *);
int lfs_q2sync(struct mount *);
int lfs_dq2get(struct vnode *, u_long, struct ulfsmount *, int, struct dquot *);
int lfs_dq2sync(struct vnode *, struct dquot *);
+901
View File
@@ -0,0 +1,901 @@
/* $NetBSD: ulfs_quota1.c,v 1.6 2013/07/28 01:10:49 dholland Exp $ */
/* from NetBSD: ufs_quota1.c,v 1.18 2012/02/02 03:00:48 matt Exp */
/*
* Copyright (c) 1982, 1986, 1990, 1993, 1995
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Robert Elz at The University of Melbourne.
*
* 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.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ulfs_quota1.c,v 1.6 2013/07/28 01:10:49 dholland Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/namei.h>
#include <sys/file.h>
#include <sys/proc.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/kauth.h>
#include <ufs/lfs/ulfs_quota1.h>
#include <ufs/lfs/ulfs_inode.h>
#include <ufs/lfs/ulfsmount.h>
#include <ufs/lfs/ulfs_extern.h>
#include <ufs/lfs/ulfs_quota.h>
static int chkdqchg(struct inode *, int64_t, kauth_cred_t, int);
static int chkiqchg(struct inode *, int32_t, kauth_cred_t, int);
/*
* Update disk usage, and take corrective action.
*/
int
lfs_chkdq1(struct inode *ip, int64_t change, kauth_cred_t cred, int flags)
{
struct dquot *dq;
int i;
int ncurblocks, error;
if ((error = lfs_getinoquota(ip)) != 0)
return error;
if (change == 0)
return (0);
if (change < 0) {
for (i = 0; i < ULFS_MAXQUOTAS; i++) {
if ((dq = ip->i_dquot[i]) == NODQUOT)
continue;
mutex_enter(&dq->dq_interlock);
ncurblocks = dq->dq_curblocks + change;
if (ncurblocks >= 0)
dq->dq_curblocks = ncurblocks;
else
dq->dq_curblocks = 0;
dq->dq_flags &= ~DQ_WARN(QL_BLOCK);
dq->dq_flags |= DQ_MOD;
mutex_exit(&dq->dq_interlock);
}
return (0);
}
for (i = 0; i < ULFS_MAXQUOTAS; i++) {
if ((dq = ip->i_dquot[i]) == NODQUOT)
continue;
if ((flags & FORCE) == 0 &&
kauth_authorize_system(cred, KAUTH_SYSTEM_FS_QUOTA,
KAUTH_REQ_SYSTEM_FS_QUOTA_NOLIMIT, KAUTH_ARG(i),
KAUTH_ARG(QL_BLOCK), NULL) != 0) {
mutex_enter(&dq->dq_interlock);
error = chkdqchg(ip, change, cred, i);
mutex_exit(&dq->dq_interlock);
if (error != 0)
return (error);
}
}
for (i = 0; i < ULFS_MAXQUOTAS; i++) {
if ((dq = ip->i_dquot[i]) == NODQUOT)
continue;
mutex_enter(&dq->dq_interlock);
dq->dq_curblocks += change;
dq->dq_flags |= DQ_MOD;
mutex_exit(&dq->dq_interlock);
}
return (0);
}
/*
* Check for a valid change to a users allocation.
* Issue an error message if appropriate.
*/
static int
chkdqchg(struct inode *ip, int64_t change, kauth_cred_t cred, int type)
{
struct dquot *dq = ip->i_dquot[type];
long ncurblocks = dq->dq_curblocks + change;
KASSERT(mutex_owned(&dq->dq_interlock));
/*
* If user would exceed their hard limit, disallow space allocation.
*/
if (ncurblocks >= dq->dq_bhardlimit && dq->dq_bhardlimit) {
if ((dq->dq_flags & DQ_WARN(QL_BLOCK)) == 0 &&
ip->i_uid == kauth_cred_geteuid(cred)) {
uprintf("\n%s: write failed, %s disk limit reached\n",
ITOV(ip)->v_mount->mnt_stat.f_mntonname,
lfs_quotatypes[type]);
dq->dq_flags |= DQ_WARN(QL_BLOCK);
}
return (EDQUOT);
}
/*
* If user is over their soft limit for too long, disallow space
* allocation. Reset time limit as they cross their soft limit.
*/
if (ncurblocks >= dq->dq_bsoftlimit && dq->dq_bsoftlimit) {
if (dq->dq_curblocks < dq->dq_bsoftlimit) {
dq->dq_btime =
time_second + ip->i_ump->umq1_btime[type];
if (ip->i_uid == kauth_cred_geteuid(cred))
uprintf("\n%s: warning, %s %s\n",
ITOV(ip)->v_mount->mnt_stat.f_mntonname,
lfs_quotatypes[type], "disk quota exceeded");
return (0);
}
if (time_second > dq->dq_btime) {
if ((dq->dq_flags & DQ_WARN(QL_BLOCK)) == 0 &&
ip->i_uid == kauth_cred_geteuid(cred)) {
uprintf("\n%s: write failed, %s %s\n",
ITOV(ip)->v_mount->mnt_stat.f_mntonname,
lfs_quotatypes[type],
"disk quota exceeded for too long");
dq->dq_flags |= DQ_WARN(QL_BLOCK);
}
return (EDQUOT);
}
}
return (0);
}
/*
* Check the inode limit, applying corrective action.
*/
int
lfs_chkiq1(struct inode *ip, int32_t change, kauth_cred_t cred, int flags)
{
struct dquot *dq;
int i;
int ncurinodes, error;
if ((error = lfs_getinoquota(ip)) != 0)
return error;
if (change == 0)
return (0);
if (change < 0) {
for (i = 0; i < ULFS_MAXQUOTAS; i++) {
if ((dq = ip->i_dquot[i]) == NODQUOT)
continue;
mutex_enter(&dq->dq_interlock);
ncurinodes = dq->dq_curinodes + change;
if (ncurinodes >= 0)
dq->dq_curinodes = ncurinodes;
else
dq->dq_curinodes = 0;
dq->dq_flags &= ~DQ_WARN(QL_FILE);
dq->dq_flags |= DQ_MOD;
mutex_exit(&dq->dq_interlock);
}
return (0);
}
for (i = 0; i < ULFS_MAXQUOTAS; i++) {
if ((dq = ip->i_dquot[i]) == NODQUOT)
continue;
if ((flags & FORCE) == 0 && kauth_authorize_system(cred,
KAUTH_SYSTEM_FS_QUOTA, KAUTH_REQ_SYSTEM_FS_QUOTA_NOLIMIT,
KAUTH_ARG(i), KAUTH_ARG(QL_FILE), NULL) != 0) {
mutex_enter(&dq->dq_interlock);
error = chkiqchg(ip, change, cred, i);
mutex_exit(&dq->dq_interlock);
if (error != 0)
return (error);
}
}
for (i = 0; i < ULFS_MAXQUOTAS; i++) {
if ((dq = ip->i_dquot[i]) == NODQUOT)
continue;
mutex_enter(&dq->dq_interlock);
dq->dq_curinodes += change;
dq->dq_flags |= DQ_MOD;
mutex_exit(&dq->dq_interlock);
}
return (0);
}
/*
* Check for a valid change to a users allocation.
* Issue an error message if appropriate.
*/
static int
chkiqchg(struct inode *ip, int32_t change, kauth_cred_t cred, int type)
{
struct dquot *dq = ip->i_dquot[type];
long ncurinodes = dq->dq_curinodes + change;
KASSERT(mutex_owned(&dq->dq_interlock));
/*
* If user would exceed their hard limit, disallow inode allocation.
*/
if (ncurinodes >= dq->dq_ihardlimit && dq->dq_ihardlimit) {
if ((dq->dq_flags & DQ_WARN(QL_FILE)) == 0 &&
ip->i_uid == kauth_cred_geteuid(cred)) {
uprintf("\n%s: write failed, %s inode limit reached\n",
ITOV(ip)->v_mount->mnt_stat.f_mntonname,
lfs_quotatypes[type]);
dq->dq_flags |= DQ_WARN(QL_FILE);
}
return (EDQUOT);
}
/*
* If user is over their soft limit for too long, disallow inode
* allocation. Reset time limit as they cross their soft limit.
*/
if (ncurinodes >= dq->dq_isoftlimit && dq->dq_isoftlimit) {
if (dq->dq_curinodes < dq->dq_isoftlimit) {
dq->dq_itime =
time_second + ip->i_ump->umq1_itime[type];
if (ip->i_uid == kauth_cred_geteuid(cred))
uprintf("\n%s: warning, %s %s\n",
ITOV(ip)->v_mount->mnt_stat.f_mntonname,
lfs_quotatypes[type], "inode quota exceeded");
return (0);
}
if (time_second > dq->dq_itime) {
if ((dq->dq_flags & DQ_WARN(QL_FILE)) == 0 &&
ip->i_uid == kauth_cred_geteuid(cred)) {
uprintf("\n%s: write failed, %s %s\n",
ITOV(ip)->v_mount->mnt_stat.f_mntonname,
lfs_quotatypes[type],
"inode quota exceeded for too long");
dq->dq_flags |= DQ_WARN(QL_FILE);
}
return (EDQUOT);
}
}
return (0);
}
int
lfsquota1_umount(struct mount *mp, int flags)
{
int i, error;
struct ulfsmount *ump = VFSTOULFS(mp);
struct lfs *fs = ump->um_lfs;
struct lwp *l = curlwp;
if ((fs->um_flags & ULFS_QUOTA) == 0)
return 0;
if ((error = vflush(mp, NULLVP, SKIPSYSTEM | flags)) != 0)
return (error);
for (i = 0; i < ULFS_MAXQUOTAS; i++) {
if (ump->um_quotas[i] != NULLVP) {
lfsquota1_handle_cmd_quotaoff(l, ump, i);
}
}
return 0;
}
/*
* Code to process quotactl commands.
*/
/*
* set up a quota file for a particular file system.
*/
int
lfsquota1_handle_cmd_quotaon(struct lwp *l, struct ulfsmount *ump, int type,
const char *fname)
{
struct mount *mp = ump->um_mountp;
struct lfs *fs = ump->um_lfs;
struct vnode *vp, **vpp, *mvp;
struct dquot *dq;
int error;
struct pathbuf *pb;
struct nameidata nd;
if (fs->um_flags & ULFS_QUOTA2) {
uprintf("%s: quotas v2 already enabled\n",
mp->mnt_stat.f_mntonname);
return (EBUSY);
}
vpp = &ump->um_quotas[type];
pb = pathbuf_create(fname);
if (pb == NULL) {
return ENOMEM;
}
NDINIT(&nd, LOOKUP, FOLLOW, pb);
if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
pathbuf_destroy(pb);
return error;
}
vp = nd.ni_vp;
pathbuf_destroy(pb);
VOP_UNLOCK(vp);
if (vp->v_type != VREG) {
(void) vn_close(vp, FREAD|FWRITE, l->l_cred);
return (EACCES);
}
if (*vpp != vp)
lfsquota1_handle_cmd_quotaoff(l, ump, type);
mutex_enter(&lfs_dqlock);
while ((ump->umq1_qflags[type] & (QTF_CLOSING | QTF_OPENING)) != 0)
cv_wait(&lfs_dqcv, &lfs_dqlock);
ump->umq1_qflags[type] |= QTF_OPENING;
mutex_exit(&lfs_dqlock);
mp->mnt_flag |= MNT_QUOTA;
vp->v_vflag |= VV_SYSTEM; /* XXXSMP */
*vpp = vp;
/*
* Save the credential of the process that turned on quotas.
* Set up the time limits for this quota.
*/
kauth_cred_hold(l->l_cred);
ump->um_cred[type] = l->l_cred;
ump->umq1_btime[type] = MAX_DQ_TIME;
ump->umq1_itime[type] = MAX_IQ_TIME;
if (lfs_dqget(NULLVP, 0, ump, type, &dq) == 0) {
if (dq->dq_btime > 0)
ump->umq1_btime[type] = dq->dq_btime;
if (dq->dq_itime > 0)
ump->umq1_itime[type] = dq->dq_itime;
lfs_dqrele(NULLVP, dq);
}
/* Allocate a marker vnode. */
mvp = vnalloc(mp);
/*
* Search vnodes associated with this mount point,
* adding references to quota file being opened.
* NB: only need to add dquot's for inodes being modified.
*/
mutex_enter(&mntvnode_lock);
again:
for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) {
vmark(mvp, vp);
mutex_enter(vp->v_interlock);
if (VTOI(vp) == NULL || vp->v_mount != mp || vismarker(vp) ||
vp->v_type == VNON || vp->v_writecount == 0 ||
(vp->v_iflag & (VI_XLOCK | VI_CLEAN)) != 0) {
mutex_exit(vp->v_interlock);
continue;
}
mutex_exit(&mntvnode_lock);
if (vget(vp, LK_EXCLUSIVE)) {
mutex_enter(&mntvnode_lock);
(void)vunmark(mvp);
goto again;
}
if ((error = lfs_getinoquota(VTOI(vp))) != 0) {
vput(vp);
mutex_enter(&mntvnode_lock);
(void)vunmark(mvp);
break;
}
vput(vp);
mutex_enter(&mntvnode_lock);
}
mutex_exit(&mntvnode_lock);
vnfree(mvp);
mutex_enter(&lfs_dqlock);
ump->umq1_qflags[type] &= ~QTF_OPENING;
cv_broadcast(&lfs_dqcv);
if (error == 0)
fs->um_flags |= ULFS_QUOTA;
mutex_exit(&lfs_dqlock);
if (error)
lfsquota1_handle_cmd_quotaoff(l, ump, type);
return (error);
}
/*
* turn off disk quotas for a filesystem.
*/
int
lfsquota1_handle_cmd_quotaoff(struct lwp *l, struct ulfsmount *ump, int type)
{
struct mount *mp = ump->um_mountp;
struct lfs *fs = ump->um_lfs;
struct vnode *vp;
struct vnode *qvp, *mvp;
struct dquot *dq;
struct inode *ip;
kauth_cred_t cred;
int i, error;
/* Allocate a marker vnode. */
mvp = vnalloc(mp);
mutex_enter(&lfs_dqlock);
while ((ump->umq1_qflags[type] & (QTF_CLOSING | QTF_OPENING)) != 0)
cv_wait(&lfs_dqcv, &lfs_dqlock);
if ((qvp = ump->um_quotas[type]) == NULLVP) {
mutex_exit(&lfs_dqlock);
vnfree(mvp);
return (0);
}
ump->umq1_qflags[type] |= QTF_CLOSING;
fs->um_flags &= ~ULFS_QUOTA;
mutex_exit(&lfs_dqlock);
/*
* Search vnodes associated with this mount point,
* deleting any references to quota file being closed.
*/
mutex_enter(&mntvnode_lock);
again:
for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) {
vmark(mvp, vp);
mutex_enter(vp->v_interlock);
if (VTOI(vp) == NULL || vp->v_mount != mp || vismarker(vp) ||
vp->v_type == VNON ||
(vp->v_iflag & (VI_XLOCK | VI_CLEAN)) != 0) {
mutex_exit(vp->v_interlock);
continue;
}
mutex_exit(&mntvnode_lock);
if (vget(vp, LK_EXCLUSIVE)) {
mutex_enter(&mntvnode_lock);
(void)vunmark(mvp);
goto again;
}
ip = VTOI(vp);
dq = ip->i_dquot[type];
ip->i_dquot[type] = NODQUOT;
lfs_dqrele(vp, dq);
vput(vp);
mutex_enter(&mntvnode_lock);
}
mutex_exit(&mntvnode_lock);
#ifdef DIAGNOSTIC
lfs_dqflush(qvp);
#endif
qvp->v_vflag &= ~VV_SYSTEM;
error = vn_close(qvp, FREAD|FWRITE, l->l_cred);
mutex_enter(&lfs_dqlock);
ump->um_quotas[type] = NULLVP;
cred = ump->um_cred[type];
ump->um_cred[type] = NOCRED;
for (i = 0; i < ULFS_MAXQUOTAS; i++)
if (ump->um_quotas[i] != NULLVP)
break;
ump->umq1_qflags[type] &= ~QTF_CLOSING;
cv_broadcast(&lfs_dqcv);
mutex_exit(&lfs_dqlock);
kauth_cred_free(cred);
if (i == ULFS_MAXQUOTAS)
mp->mnt_flag &= ~MNT_QUOTA;
return (error);
}
int
lfsquota1_handle_cmd_get(struct ulfsmount *ump, const struct quotakey *qk,
struct quotaval *qv)
{
struct dquot *dq;
int error;
struct quotaval blocks, files;
int idtype;
id_t id;
idtype = qk->qk_idtype;
id = qk->qk_id;
if (ump->um_quotas[idtype] == NULLVP)
return ENODEV;
if (id == QUOTA_DEFAULTID) { /* we want the grace period of id 0 */
if ((error = lfs_dqget(NULLVP, 0, ump, idtype, &dq)) != 0)
return error;
} else {
if ((error = lfs_dqget(NULLVP, id, ump, idtype, &dq)) != 0)
return error;
}
lfs_dqblk_to_quotavals(&dq->dq_un.dq1_dqb, &blocks, &files);
lfs_dqrele(NULLVP, dq);
if (id == QUOTA_DEFAULTID) {
if (blocks.qv_expiretime > 0)
blocks.qv_grace = blocks.qv_expiretime;
else
blocks.qv_grace = MAX_DQ_TIME;
if (files.qv_expiretime > 0)
files.qv_grace = files.qv_expiretime;
else
files.qv_grace = MAX_DQ_TIME;
}
switch (qk->qk_objtype) {
case QUOTA_OBJTYPE_BLOCKS:
*qv = blocks;
break;
case QUOTA_OBJTYPE_FILES:
*qv = files;
break;
default:
return EINVAL;
}
return 0;
}
static uint32_t
quota1_encode_limit(uint64_t lim)
{
if (lim == QUOTA_NOLIMIT || lim >= 0xffffffff) {
return 0;
}
return lim;
}
int
lfsquota1_handle_cmd_put(struct ulfsmount *ump, const struct quotakey *key,
const struct quotaval *val)
{
struct dquot *dq;
struct dqblk dqb;
int error;
switch (key->qk_idtype) {
case QUOTA_IDTYPE_USER:
case QUOTA_IDTYPE_GROUP:
break;
default:
return EINVAL;
}
switch (key->qk_objtype) {
case QUOTA_OBJTYPE_BLOCKS:
case QUOTA_OBJTYPE_FILES:
break;
default:
return EINVAL;
}
if (ump->um_quotas[key->qk_idtype] == NULLVP)
return ENODEV;
if (key->qk_id == QUOTA_DEFAULTID) {
/* just update grace times */
id_t id = 0;
if ((error = lfs_dqget(NULLVP, id, ump, key->qk_idtype, &dq)) != 0)
return error;
mutex_enter(&dq->dq_interlock);
if (val->qv_grace != QUOTA_NOTIME) {
if (key->qk_objtype == QUOTA_OBJTYPE_BLOCKS)
ump->umq1_btime[key->qk_idtype] = dq->dq_btime =
val->qv_grace;
if (key->qk_objtype == QUOTA_OBJTYPE_FILES)
ump->umq1_itime[key->qk_idtype] = dq->dq_itime =
val->qv_grace;
}
dq->dq_flags |= DQ_MOD;
mutex_exit(&dq->dq_interlock);
lfs_dqrele(NULLVP, dq);
return 0;
}
if ((error = lfs_dqget(NULLVP, key->qk_id, ump, key->qk_idtype, &dq)) != 0)
return (error);
mutex_enter(&dq->dq_interlock);
/*
* Copy all but the current values.
* Reset time limit if previously had no soft limit or were
* under it, but now have a soft limit and are over it.
*/
dqb.dqb_curblocks = dq->dq_curblocks;
dqb.dqb_curinodes = dq->dq_curinodes;
dqb.dqb_btime = dq->dq_btime;
dqb.dqb_itime = dq->dq_itime;
if (key->qk_objtype == QUOTA_OBJTYPE_BLOCKS) {
dqb.dqb_bsoftlimit = quota1_encode_limit(val->qv_softlimit);
dqb.dqb_bhardlimit = quota1_encode_limit(val->qv_hardlimit);
dqb.dqb_isoftlimit = dq->dq_isoftlimit;
dqb.dqb_ihardlimit = dq->dq_ihardlimit;
} else {
KASSERT(key->qk_objtype == QUOTA_OBJTYPE_FILES);
dqb.dqb_bsoftlimit = dq->dq_bsoftlimit;
dqb.dqb_bhardlimit = dq->dq_bhardlimit;
dqb.dqb_isoftlimit = quota1_encode_limit(val->qv_softlimit);
dqb.dqb_ihardlimit = quota1_encode_limit(val->qv_hardlimit);
}
if (dq->dq_id == 0 && val->qv_grace != QUOTA_NOTIME) {
/* also update grace time if available */
if (key->qk_objtype == QUOTA_OBJTYPE_BLOCKS) {
ump->umq1_btime[key->qk_idtype] = dqb.dqb_btime =
val->qv_grace;
}
if (key->qk_objtype == QUOTA_OBJTYPE_FILES) {
ump->umq1_itime[key->qk_idtype] = dqb.dqb_itime =
val->qv_grace;
}
}
if (dqb.dqb_bsoftlimit &&
dq->dq_curblocks >= dqb.dqb_bsoftlimit &&
(dq->dq_bsoftlimit == 0 || dq->dq_curblocks < dq->dq_bsoftlimit))
dqb.dqb_btime = time_second + ump->umq1_btime[key->qk_idtype];
if (dqb.dqb_isoftlimit &&
dq->dq_curinodes >= dqb.dqb_isoftlimit &&
(dq->dq_isoftlimit == 0 || dq->dq_curinodes < dq->dq_isoftlimit))
dqb.dqb_itime = time_second + ump->umq1_itime[key->qk_idtype];
dq->dq_un.dq1_dqb = dqb;
if (dq->dq_curblocks < dq->dq_bsoftlimit)
dq->dq_flags &= ~DQ_WARN(QL_BLOCK);
if (dq->dq_curinodes < dq->dq_isoftlimit)
dq->dq_flags &= ~DQ_WARN(QL_FILE);
if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
dq->dq_flags |= DQ_FAKE;
else
dq->dq_flags &= ~DQ_FAKE;
dq->dq_flags |= DQ_MOD;
mutex_exit(&dq->dq_interlock);
lfs_dqrele(NULLVP, dq);
return (0);
}
#if 0
/*
* Q_SETQUOTA - assign an entire dqblk structure.
*/
int
setquota1(struct mount *mp, u_long id, int type, struct dqblk *dqb)
{
struct dquot *dq;
struct dquot *ndq;
struct ulfsmount *ump = VFSTOULFS(mp);
if ((error = lfs_dqget(NULLVP, id, ump, type, &ndq)) != 0)
return (error);
dq = ndq;
mutex_enter(&dq->dq_interlock);
/*
* Copy all but the current values.
* Reset time limit if previously had no soft limit or were
* under it, but now have a soft limit and are over it.
*/
dqb->dqb_curblocks = dq->dq_curblocks;
dqb->dqb_curinodes = dq->dq_curinodes;
if (dq->dq_id != 0) {
dqb->dqb_btime = dq->dq_btime;
dqb->dqb_itime = dq->dq_itime;
}
if (dqb->dqb_bsoftlimit &&
dq->dq_curblocks >= dqb->dqb_bsoftlimit &&
(dq->dq_bsoftlimit == 0 || dq->dq_curblocks < dq->dq_bsoftlimit))
dqb->dqb_btime = time_second + ump->umq1_btime[type];
if (dqb->dqb_isoftlimit &&
dq->dq_curinodes >= dqb->dqb_isoftlimit &&
(dq->dq_isoftlimit == 0 || dq->dq_curinodes < dq->dq_isoftlimit))
dqb->dqb_itime = time_second + ump->umq1_itime[type];
dq->dq_un.dq1_dqb = *dqb;
if (dq->dq_curblocks < dq->dq_bsoftlimit)
dq->dq_flags &= ~DQ_WARN(QL_BLOCK);
if (dq->dq_curinodes < dq->dq_isoftlimit)
dq->dq_flags &= ~DQ_WARN(QL_FILE);
if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
dq->dq_flags |= DQ_FAKE;
else
dq->dq_flags &= ~DQ_FAKE;
dq->dq_flags |= DQ_MOD;
mutex_exit(&dq->dq_interlock);
lfs_dqrele(NULLVP, dq);
return (0);
}
/*
* Q_SETUSE - set current inode and block usage.
*/
int
setuse(struct mount *mp, u_long id, int type, void *addr)
{
struct dquot *dq;
struct ulfsmount *ump = VFSTOULFS(mp);
struct dquot *ndq;
struct dqblk usage;
int error;
error = copyin(addr, (void *)&usage, sizeof (struct dqblk));
if (error)
return (error);
if ((error = lfs_dqget(NULLVP, id, ump, type, &ndq)) != 0)
return (error);
dq = ndq;
mutex_enter(&dq->dq_interlock);
/*
* Reset time limit if have a soft limit and were
* previously under it, but are now over it.
*/
if (dq->dq_bsoftlimit && dq->dq_curblocks < dq->dq_bsoftlimit &&
usage.dqb_curblocks >= dq->dq_bsoftlimit)
dq->dq_btime = time_second + ump->umq1_btime[type];
if (dq->dq_isoftlimit && dq->dq_curinodes < dq->dq_isoftlimit &&
usage.dqb_curinodes >= dq->dq_isoftlimit)
dq->dq_itime = time_second + ump->umq1_itime[type];
dq->dq_curblocks = usage.dqb_curblocks;
dq->dq_curinodes = usage.dqb_curinodes;
if (dq->dq_curblocks < dq->dq_bsoftlimit)
dq->dq_flags &= ~DQ_WARN(QL_BLOCK);
if (dq->dq_curinodes < dq->dq_isoftlimit)
dq->dq_flags &= ~DQ_WARN(QL_FILE);
dq->dq_flags |= DQ_MOD;
mutex_exit(&dq->dq_interlock);
lfs_dqrele(NULLVP, dq);
return (0);
}
#endif
/*
* Q_SYNC - sync quota files to disk.
*/
int
lfs_q1sync(struct mount *mp)
{
struct ulfsmount *ump = VFSTOULFS(mp);
struct vnode *vp, *mvp;
struct dquot *dq;
int i, error;
/*
* Check if the mount point has any quotas.
* If not, simply return.
*/
for (i = 0; i < ULFS_MAXQUOTAS; i++)
if (ump->um_quotas[i] != NULLVP)
break;
if (i == ULFS_MAXQUOTAS)
return (0);
/* Allocate a marker vnode. */
mvp = vnalloc(mp);
/*
* Search vnodes associated with this mount point,
* synchronizing any modified dquot structures.
*/
mutex_enter(&mntvnode_lock);
again:
for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) {
vmark(mvp, vp);
mutex_enter(vp->v_interlock);
if (VTOI(vp) == NULL || vp->v_mount != mp || vismarker(vp) ||
vp->v_type == VNON ||
(vp->v_iflag & (VI_XLOCK | VI_CLEAN)) != 0) {
mutex_exit(vp->v_interlock);
continue;
}
mutex_exit(&mntvnode_lock);
error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT);
if (error) {
mutex_enter(&mntvnode_lock);
if (error == ENOENT) {
(void)vunmark(mvp);
goto again;
}
continue;
}
for (i = 0; i < ULFS_MAXQUOTAS; i++) {
dq = VTOI(vp)->i_dquot[i];
if (dq == NODQUOT)
continue;
mutex_enter(&dq->dq_interlock);
if (dq->dq_flags & DQ_MOD)
lfs_dq1sync(vp, dq);
mutex_exit(&dq->dq_interlock);
}
vput(vp);
mutex_enter(&mntvnode_lock);
}
mutex_exit(&mntvnode_lock);
vnfree(mvp);
return (0);
}
/*
* Obtain a dquot structure for the specified identifier and quota file
* reading the information from the file if necessary.
*/
int
lfs_dq1get(struct vnode *dqvp, u_long id, struct ulfsmount *ump, int type,
struct dquot *dq)
{
struct iovec aiov;
struct uio auio;
int error;
KASSERT(mutex_owned(&dq->dq_interlock));
vn_lock(dqvp, LK_EXCLUSIVE | LK_RETRY);
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
aiov.iov_base = (void *)&dq->dq_un.dq1_dqb;
aiov.iov_len = sizeof (struct dqblk);
auio.uio_resid = sizeof (struct dqblk);
auio.uio_offset = (off_t)(id * sizeof (struct dqblk));
auio.uio_rw = UIO_READ;
UIO_SETUP_SYSSPACE(&auio);
error = VOP_READ(dqvp, &auio, 0, ump->um_cred[type]);
if (auio.uio_resid == sizeof(struct dqblk) && error == 0)
memset((void *)&dq->dq_un.dq1_dqb, 0, sizeof(struct dqblk));
VOP_UNLOCK(dqvp);
/*
* I/O error in reading quota file, release
* quota structure and reflect problem to caller.
*/
if (error)
return (error);
/*
* Check for no limit to enforce.
* Initialize time values if necessary.
*/
if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
dq->dq_flags |= DQ_FAKE;
if (dq->dq_id != 0) {
if (dq->dq_btime == 0)
dq->dq_btime = time_second + ump->umq1_btime[type];
if (dq->dq_itime == 0)
dq->dq_itime = time_second + ump->umq1_itime[type];
}
return (0);
}
/*
* Update the disk quota in the quota file.
*/
int
lfs_dq1sync(struct vnode *vp, struct dquot *dq)
{
struct vnode *dqvp;
struct iovec aiov;
struct uio auio;
int error;
if (dq == NODQUOT)
panic("dq1sync: dquot");
KASSERT(mutex_owned(&dq->dq_interlock));
if ((dq->dq_flags & DQ_MOD) == 0)
return (0);
if ((dqvp = dq->dq_ump->um_quotas[dq->dq_type]) == NULLVP)
panic("dq1sync: file");
KASSERT(dqvp != vp);
vn_lock(dqvp, LK_EXCLUSIVE | LK_RETRY);
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
aiov.iov_base = (void *)&dq->dq_un.dq1_dqb;
aiov.iov_len = sizeof (struct dqblk);
auio.uio_resid = sizeof (struct dqblk);
auio.uio_offset = (off_t)(dq->dq_id * sizeof (struct dqblk));
auio.uio_rw = UIO_WRITE;
UIO_SETUP_SYSSPACE(&auio);
error = VOP_WRITE(dqvp, &auio, 0, dq->dq_ump->um_cred[dq->dq_type]);
if (auio.uio_resid && error == 0)
error = EIO;
dq->dq_flags &= ~DQ_MOD;
VOP_UNLOCK(dqvp);
return (error);
}
+105
View File
@@ -0,0 +1,105 @@
/* $NetBSD: ulfs_quota1.h,v 1.4 2013/06/06 00:49:28 dholland Exp $ */
/* from NetBSD: quota1.h,v 1.7 2012/08/26 02:32:14 dholland Exp */
/*
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Robert Elz at The University of Melbourne.
*
* 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.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* @(#)quota.h 8.3 (Berkeley) 8/19/94
*/
#ifndef _UFS_LFS_ULFS_QUOTA1_H_
#define _UFS_LFS_ULFS_QUOTA1_H_
#include <sys/quota.h>
#include <ufs/lfs/ulfs_quotacommon.h>
/*
* These definitions are for the original disk quota implementation, which
* is deprecated. the newer implementation is defined in quota2.h
* and friends
*/
/*
* Definitions for disk quotas imposed on the average user
* (big brother finally hits UNIX).
*
* The following constants define the amount of time given a user before the
* soft limits are treated as hard limits (usually resulting in an allocation
* failure). The timer is started when the user crosses their soft limit, it
* is reset when they go below their soft limit.
*/
#define MAX_IQ_TIME (7*24*60*60) /* seconds in 1 week */
#define MAX_DQ_TIME (7*24*60*60) /* seconds in 1 week */
#define QUOTAFILENAME "quota"
#define QUOTAGROUP "operator"
/*
* Command definitions for the 'compat_50_quotactl' system call. The commands
* are broken into a main command defined below and a subcommand that is used
* to convey the type of quota that is being manipulated (see above).
*/
#define SUBCMDMASK 0x00ff
#define SUBCMDSHIFT 8
#define QCMD(cmd, type) (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK))
#define Q_QUOTAON 0x0100 /* enable quotas */
#define Q_QUOTAOFF 0x0200 /* disable quotas */
#define Q_GETQUOTA 0x0300 /* get limits and usage */
#define Q_SETQUOTA 0x0400 /* set limits and usage */
#define Q_SETUSE 0x0500 /* set usage */
#define Q_SYNC 0x0600 /* sync disk copy of a filesystems quotas */
/*
* The following structure defines the format of the disk quota file
* (as it appears on disk) - the file is an array of these structures
* indexed by user or group number. The setquota system call establishes
* the vnode for each quota file (a pointer is retained in the ulfsmount
* structure).
*/
struct dqblk {
u_int32_t dqb_bhardlimit; /* absolute limit on disk blks alloc */
u_int32_t dqb_bsoftlimit; /* preferred limit on disk blks */
u_int32_t dqb_curblocks; /* current block count */
u_int32_t dqb_ihardlimit; /* maximum # allocated inodes + 1 */
u_int32_t dqb_isoftlimit; /* preferred inode limit */
u_int32_t dqb_curinodes; /* current # allocated inodes */
int32_t dqb_btime; /* time limit for excessive disk use */
int32_t dqb_itime; /* time limit for excessive files */
};
/* quota1_subr.c */
void lfs_dqblk_to_quotavals(const struct dqblk *,
struct quotaval *, struct quotaval *);
void lfs_quotavals_to_dqblk(const struct quotaval *, const struct quotaval *,
struct dqblk *);
#endif /* !_UFS_LFS_ULFS_QUOTA1_H_ */
+90
View File
@@ -0,0 +1,90 @@
/* $NetBSD: ulfs_quota1_subr.c,v 1.3 2013/06/06 00:49:28 dholland Exp $ */
/* from NetBSD: quota1_subr.c,v 1.7 2012/01/29 06:23:20 dholland Exp */
/*-
* Copyright (c) 2010 Manuel Bouyer
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``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 FOUNDATION OR CONTRIBUTORS
* 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>
__KERNEL_RCSID(0, "$NetBSD: ulfs_quota1_subr.c,v 1.3 2013/06/06 00:49:28 dholland Exp $");
#include <sys/types.h>
#include <machine/limits.h>
#include <sys/quota.h>
#include <ufs/lfs/ulfs_quota1.h>
static uint64_t
dqblk2q2e_limit(uint32_t lim)
{
if (lim == 0)
return UQUAD_MAX;
else
return (lim - 1);
}
static uint32_t
q2e2dqblk_limit(uint64_t lim)
{
if (lim == UQUAD_MAX)
return 0;
else
return (lim + 1);
}
void
lfs_dqblk_to_quotavals(const struct dqblk *dqblk,
struct quotaval *blocks, struct quotaval *files)
{
/* XXX is qv_grace getting handled correctly? */
blocks->qv_hardlimit = dqblk2q2e_limit(dqblk->dqb_bhardlimit);
blocks->qv_softlimit = dqblk2q2e_limit(dqblk->dqb_bsoftlimit);
blocks->qv_usage = dqblk->dqb_curblocks;
blocks->qv_expiretime = dqblk->dqb_btime;
files->qv_hardlimit = dqblk2q2e_limit(dqblk->dqb_ihardlimit);
files->qv_softlimit = dqblk2q2e_limit(dqblk->dqb_isoftlimit);
files->qv_usage = dqblk->dqb_curinodes;
files->qv_expiretime = dqblk->dqb_itime;
}
void
lfs_quotavals_to_dqblk(const struct quotaval *blocks, const struct quotaval *files,
struct dqblk *dqblk)
{
/* XXX is qv_grace getting handled correctly? */
dqblk->dqb_bhardlimit = q2e2dqblk_limit(blocks->qv_hardlimit);
dqblk->dqb_bsoftlimit = q2e2dqblk_limit(blocks->qv_softlimit);
dqblk->dqb_curblocks = blocks->qv_usage;
dqblk->dqb_btime = blocks->qv_expiretime;
dqblk->dqb_ihardlimit = q2e2dqblk_limit(files->qv_hardlimit);
dqblk->dqb_isoftlimit = q2e2dqblk_limit(files->qv_softlimit);
dqblk->dqb_curinodes = files->qv_usage;
dqblk->dqb_itime = files->qv_expiretime;
}
File diff suppressed because it is too large Load Diff
+129
View File
@@ -0,0 +1,129 @@
/* $NetBSD: ulfs_quota2.h,v 1.4 2013/06/06 00:49:28 dholland Exp $ */
/* from NetBSD: quota2.h,v 1.9 2012/02/05 14:19:04 dholland Exp */
/*-
* Copyright (c) 2010 Manuel Bouyer
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``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 FOUNDATION OR CONTRIBUTORS
* 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 _UFS_LFS_ULFS_QUOTA2_H_
#define _UFS_LFS_ULFS_QUOTA2_H_
#include <ufs/lfs/ulfs_quotacommon.h>
/* New disk quota implementation. In this implementation, the quota datas
* (default values, user limits and current usage) are part of the filesystem
* metadata. On FFS, this will be in a hidden, unlinked inode. fsck_ffs is
* responsible for checking quotas with the rest of the filesystem integrity,
* and quotas metadata are also covered by the filesystem journal if any.
* quota enable/disable is done on a filesystem basis via flags in the
* superblock
*/
/*
* The quota file is comprised of 2 parts, the header and the entries.
* The header contains global informations, and head of list of quota entries.
* A quota entry can either be in the free list, or one of the hash lists.
*/
/* description of a block or inode quota */
struct quota2_val {
uint64_t q2v_hardlimit; /* absolute limit */
uint64_t q2v_softlimit; /* overflowable limit */
uint64_t q2v_cur; /* current usage */
int64_t q2v_time; /* grace expiration date for softlimit overflow */
int64_t q2v_grace; /* allowed time for softlimit overflow */
};
/*
* On-disk description of a user or group quota
* These entries are keept as linked list, either in one of the hash HEAD,
* or in the free list.
*/
#define N_QL 2
#define QL_BLOCK 0
#define QL_FILE 1
#define INITQLNAMES { \
[QL_BLOCK] = "block", \
[QL_FILE] = "file", \
}
struct quota2_entry {
/* block & inode limits and status */
struct quota2_val q2e_val[N_QL];
/* pointer to next entry for this list (offset in the file) */
uint64_t q2e_next;
/* ownership information */
uint32_t q2e_uid;
uint32_t q2e_pad;
};
/* header present at the start of the quota file */
struct quota2_header {
uint32_t q2h_magic_number;
uint8_t q2h_type; /* quota type, see below */
uint8_t q2h_hash_shift; /* bytes used for hash index */
uint16_t q2h_hash_size; /* size of hash table */
/* default values applied to new entries */
struct quota2_entry q2h_defentry;
/* head of free quota2_entry list */
uint64_t q2h_free;
/* variable-sized hash table */
uint64_t q2h_entries[0];
};
#define Q2_HEAD_MAGIC 0xb746915e
/* superblock flags */
#define FS_Q2_DO_TYPE(type) (0x01 << (type))
#define off2qindex(hsize, off) (((off) - (hsize)) / sizeof(struct quota2_entry))
#define qindex2off(hsize, idx) \
((daddr_t)(idx) * sizeof(struct quota2_entry) + (hsize))
/* quota2_subr.c */
void lfsquota2_addfreeq2e(struct quota2_header *, void *, uint64_t, uint64_t, int);
void lfsquota2_create_blk0(uint64_t, void *bp, int, int, int);
void lfsquota2_ulfs_rwq2v(const struct quota2_val *, struct quota2_val *, int);
void lfsquota2_ulfs_rwq2e(const struct quota2_entry *, struct quota2_entry *, int);
/*
* Return codes for lfsquota_check_limit()
*/
#define QL_S_ALLOW_OK 0x00 /* below soft limit */
#define QL_S_ALLOW_SOFT 0x01 /* over soft limit */
#define QL_S_DENY_GRACE 0x02 /* over soft limit, grace time expired */
#define QL_S_DENY_HARD 0x03 /* over hard limit */
#define QL_F_CROSS 0x80 /* crossing soft limit */
#define QL_STATUS(x) ((x) & 0x0f)
#define QL_FLAGS(x) ((x) & 0xf0)
/* check a quota usage against limits */
int lfsquota_check_limit(uint64_t, uint64_t, uint64_t, uint64_t, time_t, time_t);
#endif /* _UFS_LFS_ULFS_QUOTA2_H_ */
+130
View File
@@ -0,0 +1,130 @@
/* $NetBSD: ulfs_quota2_subr.c,v 1.6 2013/06/06 00:51:50 dholland Exp $ */
/* from NetBSD: quota2_subr.c,v 1.5 2012/02/05 14:19:04 dholland Exp */
/*-
* Copyright (c) 2010, 2011 Manuel Bouyer
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``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 FOUNDATION OR CONTRIBUTORS
* 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>
__KERNEL_RCSID(0, "$NetBSD: ulfs_quota2_subr.c,v 1.6 2013/06/06 00:51:50 dholland Exp $");
#include <sys/param.h>
#include <sys/time.h>
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_extern.h>
#include <ufs/lfs/ulfs_inode.h>
#include <ufs/lfs/ulfs_dinode.h>
#include <ufs/lfs/ulfs_bswap.h>
#include <ufs/lfs/ulfs_quota2.h>
#ifndef _KERNEL
#include <string.h>
#endif
void
lfsquota2_addfreeq2e(struct quota2_header *q2h, void *bp, uint64_t baseoff,
uint64_t bsize, int ns)
{
uint64_t blkoff = baseoff % bsize;
int i, nq2e;
struct quota2_entry *q2e;
q2e = (void *)((char *)bp + blkoff);
nq2e = (bsize - blkoff) / sizeof(*q2e);
for (i = 0; i < nq2e; i++) {
q2e[i].q2e_next = q2h->q2h_free;
q2h->q2h_free = ulfs_rw64(i * sizeof(*q2e) + baseoff, ns);
}
}
void
lfsquota2_create_blk0(uint64_t bsize, void *bp, int q2h_hash_shift, int type,
int ns)
{
struct quota2_header *q2h;
const int quota2_hash_size = 1 << q2h_hash_shift;
const int quota2_full_header_size = sizeof(struct quota2_header) +
sizeof(q2h->q2h_entries[0]) * quota2_hash_size;
int i;
memset(bp, 0, bsize);
q2h = bp;
q2h->q2h_magic_number = ulfs_rw32(Q2_HEAD_MAGIC, ns);
q2h->q2h_type = type;
q2h->q2h_hash_shift = q2h_hash_shift;
q2h->q2h_hash_size = ulfs_rw16(quota2_hash_size, ns);
/* setup defaut entry: unlimited, 7 days grace */
for (i = 0; i < N_QL; i++) {
q2h->q2h_defentry.q2e_val[i].q2v_hardlimit =
q2h->q2h_defentry.q2e_val[i].q2v_softlimit =
ulfs_rw64(UQUAD_MAX, ns);
q2h->q2h_defentry.q2e_val[i].q2v_grace =
ulfs_rw64(7ULL * 24ULL * 3600ULL, ns);
}
/* first quota entry, after the hash table */
lfsquota2_addfreeq2e(q2h, bp, quota2_full_header_size, bsize, ns);
}
void
lfsquota2_ulfs_rwq2v(const struct quota2_val *s, struct quota2_val *d, int needswap)
{
d->q2v_hardlimit = ulfs_rw64(s->q2v_hardlimit, needswap);
d->q2v_softlimit = ulfs_rw64(s->q2v_softlimit, needswap);
d->q2v_cur = ulfs_rw64(s->q2v_cur, needswap);
d->q2v_time = ulfs_rw64(s->q2v_time, needswap);
d->q2v_grace = ulfs_rw64(s->q2v_grace, needswap);
}
void
lfsquota2_ulfs_rwq2e(const struct quota2_entry *s, struct quota2_entry *d,
int needswap)
{
lfsquota2_ulfs_rwq2v(&s->q2e_val[QL_BLOCK], &d->q2e_val[QL_BLOCK],
needswap);
lfsquota2_ulfs_rwq2v(&s->q2e_val[QL_FILE], &d->q2e_val[QL_FILE],
needswap);
d->q2e_uid = ulfs_rw32(s->q2e_uid, needswap);
}
int
lfsquota_check_limit(uint64_t cur, uint64_t change, uint64_t soft, uint64_t hard,
time_t expire, time_t now)
{
if (cur + change > hard) {
if (cur <= soft)
return (QL_F_CROSS | QL_S_DENY_HARD);
return QL_S_DENY_HARD;
} else if (cur + change > soft) {
if (cur <= soft)
return (QL_F_CROSS | QL_S_ALLOW_SOFT);
if (now > expire) {
return QL_S_DENY_GRACE;
}
return QL_S_ALLOW_SOFT;
}
return QL_S_ALLOW_OK;
}
+98
View File
@@ -0,0 +1,98 @@
/* $NetBSD: ulfs_quotacommon.h,v 1.4 2013/06/08 02:04:31 dholland Exp $ */
/* from NetBSD: quota.h,v 1.30 2012/08/26 02:32:14 dholland Exp */
/*
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Robert Elz at The University of Melbourne.
*
* 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.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* @(#)quota.h 8.3 (Berkeley) 8/19/94
*/
#ifndef _UFS_LFS_ULFS_QUOTACOMMON_H_
#define _UFS_LFS_ULFS_QUOTACOMMON_H_
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_inode.h>
/*
* These definitions are common to the original disk quota implementation
* (quota1) and the newer implementation (quota2)
*/
/*
* Initializer for the strings corresponding to the quota ID types.
* (in quota1 these are also the default names of the quota files)
*/
#define INITQFNAMES { \
"user", /* ULFS_USRQUOTA */ \
"group", /* ULFS_GRPQUOTA */ \
}
#if !defined(HAVE_NBTOOL_CONFIG_H)
#include <sys/quota.h>
__inline static int __unused
quota_idtype_to_ulfs(int idtype)
{
switch (idtype) {
case QUOTA_IDTYPE_USER:
return ULFS_USRQUOTA;
case QUOTA_IDTYPE_GROUP:
return ULFS_GRPQUOTA;
default:
return -1;
}
}
static __inline int __unused
quota_idtype_from_ulfs(int ulfstype)
{
switch (ulfstype) {
case ULFS_USRQUOTA:
return QUOTA_IDTYPE_USER;
case ULFS_GRPQUOTA:
return QUOTA_IDTYPE_GROUP;
default:
return -1;
}
}
#endif /* !defined(HAVE_NBTOOL_CONFIG_H) */
#ifdef _KERNEL
#include <sys/cdefs.h>
__BEGIN_DECLS
void lfs_dqinit(void);
void lfs_dqreinit(void);
void lfs_dqdone(void);
__END_DECLS
#endif /* _KERNEL */
#endif /* !_UFS_LFS_ULFS_QUOTACOMMON_H_ */
+527
View File
@@ -0,0 +1,527 @@
/* $NetBSD: ulfs_readwrite.c,v 1.7 2013/10/17 21:01:08 christos Exp $ */
/* from NetBSD: ufs_readwrite.c,v 1.105 2013/01/22 09:39:18 dholland Exp */
/*-
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* @(#)ufs_readwrite.c 8.11 (Berkeley) 5/8/95
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(1, "$NetBSD: ulfs_readwrite.c,v 1.7 2013/10/17 21:01:08 christos Exp $");
#ifdef LFS_READWRITE
#define FS struct lfs
#define I_FS i_lfs
#define READ lfs_read
#define READ_S "lfs_read"
#define WRITE lfs_write
#define WRITE_S "lfs_write"
#define fs_bsize lfs_bsize
#define fs_bmask lfs_bmask
#else
#define FS struct fs
#define I_FS i_fs
#define READ ffs_read
#define READ_S "ffs_read"
#define WRITE ffs_write
#define WRITE_S "ffs_write"
#endif
/*
* Vnode op for reading.
*/
/* ARGSUSED */
int
READ(void *v)
{
struct vop_read_args /* {
struct vnode *a_vp;
struct uio *a_uio;
int a_ioflag;
kauth_cred_t a_cred;
} */ *ap = v;
struct vnode *vp;
struct inode *ip;
struct uio *uio;
struct buf *bp;
FS *fs;
vsize_t bytelen;
daddr_t lbn, nextlbn;
off_t bytesinfile;
long size, xfersize, blkoffset;
int error, ioflag;
bool usepc = false;
vp = ap->a_vp;
ip = VTOI(vp);
fs = ip->I_FS;
uio = ap->a_uio;
ioflag = ap->a_ioflag;
error = 0;
#ifdef DIAGNOSTIC
if (uio->uio_rw != UIO_READ)
panic("%s: mode", READ_S);
if (vp->v_type == VLNK) {
if (ip->i_size < fs->um_maxsymlinklen ||
(fs->um_maxsymlinklen == 0 && DIP(ip, blocks) == 0))
panic("%s: short symlink", READ_S);
} else if (vp->v_type != VREG && vp->v_type != VDIR)
panic("%s: type %d", READ_S, vp->v_type);
#endif
if ((u_int64_t)uio->uio_offset > fs->um_maxfilesize)
return (EFBIG);
if (uio->uio_resid == 0)
return (0);
#ifndef LFS_READWRITE
if ((ip->i_flags & (SF_SNAPSHOT | SF_SNAPINVAL)) == SF_SNAPSHOT)
return ffs_snapshot_read(vp, uio, ioflag);
#endif /* !LFS_READWRITE */
fstrans_start(vp->v_mount, FSTRANS_SHARED);
if (uio->uio_offset >= ip->i_size)
goto out;
#ifdef LFS_READWRITE
usepc = (vp->v_type == VREG && ip->i_number != LFS_IFILE_INUM);
#else /* !LFS_READWRITE */
usepc = vp->v_type == VREG;
#endif /* !LFS_READWRITE */
if (usepc) {
const int advice = IO_ADV_DECODE(ap->a_ioflag);
while (uio->uio_resid > 0) {
if (ioflag & IO_DIRECT) {
genfs_directio(vp, uio, ioflag);
}
bytelen = MIN(ip->i_size - uio->uio_offset,
uio->uio_resid);
if (bytelen == 0)
break;
error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice,
UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp));
if (error)
break;
}
goto out;
}
for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
bytesinfile = ip->i_size - uio->uio_offset;
if (bytesinfile <= 0)
break;
lbn = lfs_lblkno(fs, uio->uio_offset);
nextlbn = lbn + 1;
size = lfs_blksize(fs, ip, lbn);
blkoffset = lfs_blkoff(fs, uio->uio_offset);
xfersize = MIN(MIN(fs->fs_bsize - blkoffset, uio->uio_resid),
bytesinfile);
if (lfs_lblktosize(fs, nextlbn) >= ip->i_size)
error = bread(vp, lbn, size, NOCRED, 0, &bp);
else {
int nextsize = lfs_blksize(fs, ip, nextlbn);
error = breadn(vp, lbn,
size, &nextlbn, &nextsize, 1, NOCRED, 0, &bp);
}
if (error)
break;
/*
* We should only get non-zero b_resid when an I/O error
* has occurred, which should cause us to break above.
* However, if the short read did not cause an error,
* then we want to ensure that we do not uiomove bad
* or uninitialized data.
*/
size -= bp->b_resid;
if (size < xfersize) {
if (size == 0)
break;
xfersize = size;
}
error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio);
if (error)
break;
brelse(bp, 0);
}
if (bp != NULL)
brelse(bp, 0);
out:
if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) {
ip->i_flag |= IN_ACCESS;
if ((ap->a_ioflag & IO_SYNC) == IO_SYNC) {
error = lfs_update(vp, NULL, NULL, UPDATE_WAIT);
}
}
fstrans_done(vp->v_mount);
return (error);
}
/*
* Vnode op for writing.
*/
int
WRITE(void *v)
{
struct vop_write_args /* {
struct vnode *a_vp;
struct uio *a_uio;
int a_ioflag;
kauth_cred_t a_cred;
} */ *ap = v;
struct vnode *vp;
struct uio *uio;
struct inode *ip;
FS *fs;
struct buf *bp;
kauth_cred_t cred;
daddr_t lbn;
off_t osize, origoff, oldoff, preallocoff, endallocoff, nsize;
int blkoffset, error, flags, ioflag, resid, size, xfersize;
int aflag;
int extended=0;
vsize_t bytelen;
bool async;
bool usepc = false;
#ifdef LFS_READWRITE
bool need_unreserve = false;
#endif
cred = ap->a_cred;
ioflag = ap->a_ioflag;
uio = ap->a_uio;
vp = ap->a_vp;
ip = VTOI(vp);
KASSERT(vp->v_size == ip->i_size);
#ifdef DIAGNOSTIC
if (uio->uio_rw != UIO_WRITE)
panic("%s: mode", WRITE_S);
#endif
switch (vp->v_type) {
case VREG:
if (ioflag & IO_APPEND)
uio->uio_offset = ip->i_size;
if ((ip->i_flags & APPEND) && uio->uio_offset != ip->i_size)
return (EPERM);
/* FALLTHROUGH */
case VLNK:
break;
case VDIR:
if ((ioflag & IO_SYNC) == 0)
panic("%s: nonsync dir write", WRITE_S);
break;
default:
panic("%s: type", WRITE_S);
}
fs = ip->I_FS;
if (uio->uio_offset < 0 ||
(u_int64_t)uio->uio_offset + uio->uio_resid > fs->um_maxfilesize)
return (EFBIG);
#ifdef LFS_READWRITE
/* Disallow writes to the Ifile, even if noschg flag is removed */
/* XXX can this go away when the Ifile is no longer in the namespace? */
if (vp == fs->lfs_ivnode)
return (EPERM);
#endif
if (uio->uio_resid == 0)
return (0);
fstrans_start(vp->v_mount, FSTRANS_SHARED);
flags = ioflag & IO_SYNC ? B_SYNC : 0;
async = vp->v_mount->mnt_flag & MNT_ASYNC;
origoff = uio->uio_offset;
resid = uio->uio_resid;
osize = ip->i_size;
error = 0;
usepc = vp->v_type == VREG;
#ifdef LFS_READWRITE
async = true;
lfs_availwait(fs, lfs_btofsb(fs, uio->uio_resid));
lfs_check(vp, LFS_UNUSED_LBN, 0);
#endif /* !LFS_READWRITE */
if (!usepc)
goto bcache;
preallocoff = round_page(lfs_blkroundup(fs, MAX(osize, uio->uio_offset)));
aflag = ioflag & IO_SYNC ? B_SYNC : 0;
nsize = MAX(osize, uio->uio_offset + uio->uio_resid);
endallocoff = nsize - lfs_blkoff(fs, nsize);
/*
* if we're increasing the file size, deal with expanding
* the fragment if there is one.
*/
if (nsize > osize && lfs_lblkno(fs, osize) < ULFS_NDADDR &&
lfs_lblkno(fs, osize) != lfs_lblkno(fs, nsize) &&
lfs_blkroundup(fs, osize) != osize) {
off_t eob;
eob = lfs_blkroundup(fs, osize);
uvm_vnp_setwritesize(vp, eob);
error = ulfs_balloc_range(vp, osize, eob - osize, cred, aflag);
if (error)
goto out;
if (flags & B_SYNC) {
mutex_enter(vp->v_interlock);
VOP_PUTPAGES(vp, trunc_page(osize & fs->fs_bmask),
round_page(eob),
PGO_CLEANIT | PGO_SYNCIO | PGO_JOURNALLOCKED);
}
}
while (uio->uio_resid > 0) {
int ubc_flags = UBC_WRITE;
bool overwrite; /* if we're overwrite a whole block */
off_t newoff;
if (ioflag & IO_DIRECT) {
genfs_directio(vp, uio, ioflag | IO_JOURNALLOCKED);
}
oldoff = uio->uio_offset;
blkoffset = lfs_blkoff(fs, uio->uio_offset);
bytelen = MIN(fs->fs_bsize - blkoffset, uio->uio_resid);
if (bytelen == 0) {
break;
}
/*
* if we're filling in a hole, allocate the blocks now and
* initialize the pages first. if we're extending the file,
* we can safely allocate blocks without initializing pages
* since the new blocks will be inaccessible until the write
* is complete.
*/
overwrite = uio->uio_offset >= preallocoff &&
uio->uio_offset < endallocoff;
if (!overwrite && (vp->v_vflag & VV_MAPPED) == 0 &&
lfs_blkoff(fs, uio->uio_offset) == 0 &&
(uio->uio_offset & PAGE_MASK) == 0) {
vsize_t len;
len = trunc_page(bytelen);
len -= lfs_blkoff(fs, len);
if (len > 0) {
overwrite = true;
bytelen = len;
}
}
newoff = oldoff + bytelen;
if (vp->v_size < newoff) {
uvm_vnp_setwritesize(vp, newoff);
}
if (!overwrite) {
error = ulfs_balloc_range(vp, uio->uio_offset, bytelen,
cred, aflag);
if (error)
break;
} else {
genfs_node_wrlock(vp);
error = GOP_ALLOC(vp, uio->uio_offset, bytelen,
aflag, cred);
genfs_node_unlock(vp);
if (error)
break;
ubc_flags |= UBC_FAULTBUSY;
}
/*
* copy the data.
*/
error = ubc_uiomove(&vp->v_uobj, uio, bytelen,
IO_ADV_DECODE(ioflag), ubc_flags | UBC_UNMAP_FLAG(vp));
/*
* update UVM's notion of the size now that we've
* copied the data into the vnode's pages.
*
* we should update the size even when uiomove failed.
*/
if (vp->v_size < newoff) {
uvm_vnp_setsize(vp, newoff);
extended = 1;
}
if (error)
break;
/*
* flush what we just wrote if necessary.
* XXXUBC simplistic async flushing.
*/
#ifndef LFS_READWRITE
if (!async && oldoff >> 16 != uio->uio_offset >> 16) {
mutex_enter(vp->v_interlock);
error = VOP_PUTPAGES(vp, (oldoff >> 16) << 16,
(uio->uio_offset >> 16) << 16,
PGO_CLEANIT | PGO_JOURNALLOCKED | PGO_LAZY);
if (error)
break;
}
#else
__USE(async);
#endif
}
if (error == 0 && ioflag & IO_SYNC) {
mutex_enter(vp->v_interlock);
error = VOP_PUTPAGES(vp, trunc_page(origoff & fs->fs_bmask),
round_page(lfs_blkroundup(fs, uio->uio_offset)),
PGO_CLEANIT | PGO_SYNCIO | PGO_JOURNALLOCKED);
}
goto out;
bcache:
mutex_enter(vp->v_interlock);
VOP_PUTPAGES(vp, trunc_page(origoff), round_page(origoff + resid),
PGO_CLEANIT | PGO_FREE | PGO_SYNCIO | PGO_JOURNALLOCKED);
while (uio->uio_resid > 0) {
lbn = lfs_lblkno(fs, uio->uio_offset);
blkoffset = lfs_blkoff(fs, uio->uio_offset);
xfersize = MIN(fs->fs_bsize - blkoffset, uio->uio_resid);
if (fs->fs_bsize > xfersize)
flags |= B_CLRBUF;
else
flags &= ~B_CLRBUF;
#ifdef LFS_READWRITE
error = lfs_reserve(fs, vp, NULL,
lfs_btofsb(fs, (ULFS_NIADDR + 1) << fs->lfs_bshift));
if (error)
break;
need_unreserve = true;
#endif
error = lfs_balloc(vp, uio->uio_offset, xfersize,
ap->a_cred, flags, &bp);
if (error)
break;
if (uio->uio_offset + xfersize > ip->i_size) {
ip->i_size = uio->uio_offset + xfersize;
DIP_ASSIGN(ip, size, ip->i_size);
uvm_vnp_setsize(vp, ip->i_size);
extended = 1;
}
size = lfs_blksize(fs, ip, lbn) - bp->b_resid;
if (xfersize > size)
xfersize = size;
error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio);
/*
* if we didn't clear the block and the uiomove failed,
* the buf will now contain part of some other file,
* so we need to invalidate it.
*/
if (error && (flags & B_CLRBUF) == 0) {
brelse(bp, BC_INVAL);
break;
}
#ifdef LFS_READWRITE
(void)VOP_BWRITE(bp->b_vp, bp);
lfs_reserve(fs, vp, NULL,
-lfs_btofsb(fs, (ULFS_NIADDR + 1) << fs->lfs_bshift));
need_unreserve = false;
#else
if (ioflag & IO_SYNC)
(void)bwrite(bp);
else if (xfersize + blkoffset == fs->fs_bsize)
bawrite(bp);
else
bdwrite(bp);
#endif
if (error || xfersize == 0)
break;
}
#ifdef LFS_READWRITE
if (need_unreserve) {
lfs_reserve(fs, vp, NULL,
-lfs_btofsb(fs, (ULFS_NIADDR + 1) << fs->lfs_bshift));
}
#endif
/*
* If we successfully wrote any data, and we are not the superuser
* we clear the setuid and setgid bits as a precaution against
* tampering.
*/
out:
ip->i_flag |= IN_CHANGE | IN_UPDATE;
if (vp->v_mount->mnt_flag & MNT_RELATIME)
ip->i_flag |= IN_ACCESS;
if (resid > uio->uio_resid && ap->a_cred) {
if (ip->i_mode & ISUID) {
if (kauth_authorize_vnode(ap->a_cred,
KAUTH_VNODE_RETAIN_SUID, vp, NULL, EPERM) != 0) {
ip->i_mode &= ~ISUID;
DIP_ASSIGN(ip, mode, ip->i_mode);
}
}
if (ip->i_mode & ISGID) {
if (kauth_authorize_vnode(ap->a_cred,
KAUTH_VNODE_RETAIN_SGID, vp, NULL, EPERM) != 0) {
ip->i_mode &= ~ISGID;
DIP_ASSIGN(ip, mode, ip->i_mode);
}
}
}
if (resid > uio->uio_resid)
VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0));
if (error) {
(void) lfs_truncate(vp, osize, ioflag & IO_SYNC, ap->a_cred);
uio->uio_offset -= resid - uio->uio_resid;
uio->uio_resid = resid;
} else if (resid > uio->uio_resid && (ioflag & IO_SYNC) == IO_SYNC) {
error = lfs_update(vp, NULL, NULL, UPDATE_WAIT);
} else {
/* nothing */
}
KASSERT(vp->v_size == ip->i_size);
fstrans_done(vp->v_mount);
return (error);
}
+89
View File
@@ -0,0 +1,89 @@
/* $NetBSD: ulfs_snapshot.c,v 1.2 2013/06/08 22:05:15 dholland Exp $ */
/* from ffs_snapshot.c,v 1.122 2013/05/07 09:40:54 hannken Exp */
/*
* Copyright 2000 Marshall Kirk McKusick. All Rights Reserved.
*
* Further information about snapshots can be obtained from:
*
* Marshall Kirk McKusick http://www.mckusick.com/softdep/
* 1614 Oxford Street mckusick@mckusick.com
* Berkeley, CA 94709-1608 +1-510-843-9542
* USA
*
* 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 MARSHALL KIRK MCKUSICK ``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 MARSHALL KIRK MCKUSICK 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.
*
* @(#)ffs_snapshot.c 8.11 (McKusick) 7/23/00
*
* from FreeBSD: ffs_snapshot.c,v 1.79 2004/02/13 02:02:06 kuriyama Exp
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ulfs_snapshot.c,v 1.2 2013/06/08 22:05:15 dholland Exp $");
#if defined(_KERNEL_OPT)
#include "opt_lfs.h"
#endif
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/buf.h>
#include <sys/proc.h>
#include <sys/namei.h>
#include <sys/sched.h>
#include <sys/stat.h>
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/resource.h>
#include <sys/resourcevar.h>
#include <sys/vnode.h>
#include <sys/kauth.h>
#include <sys/fstrans.h>
#include <sys/wapbl.h>
#include <miscfs/specfs/specdev.h>
#include <ufs/lfs/ulfs_quotacommon.h>
#include <ufs/lfs/ulfsmount.h>
#include <ufs/lfs/ulfs_inode.h>
#include <ufs/lfs/ulfs_extern.h>
#include <ufs/lfs/ulfs_bswap.h>
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_extern.h>
#include <uvm/uvm.h>
/*
* Decrement extra reference on snapshot when last name is removed.
* It will not be freed until the last open reference goes away.
*/
void
ulfs_snapgone(struct inode *ip)
{
(void)ip;
/* just panic */
panic("reached ulfs_snapgone\n");
}
+291
View File
@@ -0,0 +1,291 @@
/* $NetBSD: ulfs_vfsops.c,v 1.8 2013/06/08 02:12:56 dholland Exp $ */
/* from NetBSD: ufs_vfsops.c,v 1.52 2013/01/22 09:39:18 dholland Exp */
/*
* Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* 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.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* @(#)ufs_vfsops.c 8.8 (Berkeley) 5/20/95
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ulfs_vfsops.c,v 1.8 2013/06/08 02:12:56 dholland Exp $");
#if defined(_KERNEL_OPT)
#include "opt_lfs.h"
#include "opt_quota.h"
#endif
#include <sys/param.h>
#include <sys/mbuf.h>
#include <sys/mount.h>
#include <sys/proc.h>
#include <sys/buf.h>
#include <sys/vnode.h>
#include <sys/kmem.h>
#include <sys/kauth.h>
#include <sys/quotactl.h>
#include <miscfs/specfs/specdev.h>
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/ulfs_quotacommon.h>
#include <ufs/lfs/ulfs_inode.h>
#include <ufs/lfs/ulfsmount.h>
#include <ufs/lfs/ulfs_extern.h>
#ifdef LFS_DIRHASH
#include <ufs/lfs/ulfs_dirhash.h>
#endif
/* how many times ulfs_init() was called */
static int ulfs_initcount = 0;
pool_cache_t ulfs_direct_cache;
/*
* Make a filesystem operational.
* Nothing to do at the moment.
*/
/* ARGSUSED */
int
ulfs_start(struct mount *mp, int flags)
{
return (0);
}
/*
* Return the root of a filesystem.
*/
int
ulfs_root(struct mount *mp, struct vnode **vpp)
{
struct vnode *nvp;
int error;
if ((error = VFS_VGET(mp, (ino_t)ULFS_ROOTINO, &nvp)) != 0)
return (error);
*vpp = nvp;
return (0);
}
/*
* Do operations associated with quotas
*/
int
ulfs_quotactl(struct mount *mp, struct quotactl_args *args)
{
#if !defined(LFS_QUOTA) && !defined(LFS_QUOTA2)
(void) mp;
(void) args;
return (EOPNOTSUPP);
#else
struct lwp *l = curlwp;
int error;
/* Mark the mount busy, as we're passing it to kauth(9). */
error = vfs_busy(mp, NULL);
if (error) {
return (error);
}
mutex_enter(&mp->mnt_updating);
error = lfsquota_handle_cmd(mp, l, args);
mutex_exit(&mp->mnt_updating);
vfs_unbusy(mp, false, NULL);
return (error);
#endif
}
#if 0
switch (cmd) {
case Q_SYNC:
break;
case Q_GETQUOTA:
/* The user can always query about his own quota. */
if (uid == kauth_cred_getuid(l->l_cred))
break;
error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, KAUTH_ARG(uid), NULL);
break;
case Q_QUOTAON:
case Q_QUOTAOFF:
error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL);
break;
case Q_SETQUOTA:
case Q_SETUSE:
error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(uid), NULL);
break;
default:
error = EINVAL;
break;
}
type = cmds & SUBCMDMASK;
if (!error) {
/* Only check if there was no error above. */
if ((u_int)type >= MAXQUOTAS)
error = EINVAL;
}
if (error) {
vfs_unbusy(mp, false, NULL);
return (error);
}
mutex_enter(&mp->mnt_updating);
switch (cmd) {
case Q_QUOTAON:
error = quotaon(l, mp, type, arg);
break;
case Q_QUOTAOFF:
error = quotaoff(l, mp, type);
break;
case Q_SETQUOTA:
error = setquota(mp, uid, type, arg);
break;
case Q_SETUSE:
error = setuse(mp, uid, type, arg);
break;
case Q_GETQUOTA:
error = getquota(mp, uid, type, arg);
break;
case Q_SYNC:
error = lfs_qsync(mp);
break;
default:
error = EINVAL;
}
mutex_exit(&mp->mnt_updating);
vfs_unbusy(mp, false, NULL);
return (error);
#endif
/*
* This is the generic part of fhtovp called after the underlying
* filesystem has validated the file handle.
*/
int
ulfs_fhtovp(struct mount *mp, struct ulfs_ufid *ufhp, struct vnode **vpp)
{
struct vnode *nvp;
struct inode *ip;
int error;
if ((error = VFS_VGET(mp, ufhp->ufid_ino, &nvp)) != 0) {
*vpp = NULLVP;
return (error);
}
ip = VTOI(nvp);
KASSERT(ip != NULL);
if (ip->i_mode == 0 || ip->i_gen != ufhp->ufid_gen) {
vput(nvp);
*vpp = NULLVP;
return (ESTALE);
}
*vpp = nvp;
return (0);
}
/*
* Initialize ULFS filesystems, done only once.
*/
void
ulfs_init(void)
{
if (ulfs_initcount++ > 0)
return;
ulfs_direct_cache = pool_cache_init(sizeof(struct lfs_direct), 0, 0, 0,
"ulfsdir", NULL, IPL_NONE, NULL, NULL, NULL);
ulfs_ihashinit();
#if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
lfs_dqinit();
#endif
#ifdef LFS_DIRHASH
ulfsdirhash_init();
#endif
#ifdef LFS_EXTATTR
ulfs_extattr_init();
#endif
}
void
ulfs_reinit(void)
{
ulfs_ihashreinit();
#if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
lfs_dqreinit();
#endif
}
/*
* Free ULFS filesystem resources, done only once.
*/
void
ulfs_done(void)
{
if (--ulfs_initcount > 0)
return;
ulfs_ihashdone();
#if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
lfs_dqdone();
#endif
pool_cache_destroy(ulfs_direct_cache);
#ifdef LFS_DIRHASH
ulfsdirhash_done();
#endif
#ifdef LFS_EXTATTR
ulfs_extattr_done();
#endif
}
File diff suppressed because it is too large Load Diff
+134
View File
@@ -0,0 +1,134 @@
/* $NetBSD: ulfsmount.h,v 1.12 2013/07/28 01:10:49 dholland Exp $ */
/* from NetBSD: ufsmount.h,v 1.39 2012/10/19 17:09:08 drochner Exp */
/*
* Copyright (c) 1982, 1986, 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* @(#)ufsmount.h 8.6 (Berkeley) 3/30/95
*/
#ifndef _UFS_LFS_ULFSMOUNT_H_
#define _UFS_LFS_ULFSMOUNT_H_
#include <sys/mount.h> /* struct export_args30 */
#ifdef _KERNEL
#if defined(_KERNEL_OPT)
#include "opt_lfs.h"
#endif
#include <sys/mutex.h>
#include <ufs/lfs/ulfs_extattr.h>
#include <ufs/lfs/ulfs_quotacommon.h>
struct buf;
struct inode;
struct nameidata;
struct timeval;
struct uio;
struct vnode;
/* This structure describes the ULFS specific mount structure data. */
struct ulfsmount {
/* Abstract vfs-level filesystem structure. */
struct mount *um_mountp;
/* The block device we're mounted on. */
dev_t um_dev;
struct vnode *um_devvp;
/* type of fs; currently always ULFS1, theoretically also ULFS2 */
u_long um_fstype;
/* pointer to the filesystem-specific filesystem structure */
struct lfs *um_lfs;
/* Extended attribute information. */
struct ulfs_extattr_per_mount um_extattr;
/* Quota-related material. */
struct vnode *um_quotas[ULFS_MAXQUOTAS]; /* quota files */
kauth_cred_t um_cred[ULFS_MAXQUOTAS]; /* quota file access cred */
union {
struct um_q1 {
time_t q1_btime[ULFS_MAXQUOTAS]; /* block quota time limit */
time_t q1_itime[ULFS_MAXQUOTAS]; /* inode quota time limit */
char q1_qflags[ULFS_MAXQUOTAS]; /* quota flags */
} um_q1;
struct um_q2 {
uint64_t q2_bsize; /* block size of quota file */
uint64_t q2_bmask; /* mask for above */
} um_q2;
} um_q;
#define umq1_btime um_q.um_q1.q1_btime
#define umq1_itime um_q.um_q1.q1_itime
#define umq1_qflags um_q.um_q1.q1_qflags
#define umq2_bsize um_q.um_q2.q2_bsize
#define umq2_bmask um_q.um_q2.q2_bmask
};
/* ULFS-specific flags for um_flags */
#define ULFS_NEEDSWAP 0x01 /* filesystem metadata need byte-swapping */
/* unused 0x02 */
#define ULFS_QUOTA 0x04 /* filesystem has QUOTA (v1) */
#define ULFS_QUOTA2 0x08 /* filesystem has QUOTA2 */
/*
* Filesystem types
*/
#define ULFS1 1
#define ULFS2 2
/*
* Flags describing the state of quotas.
*/
#define QTF_OPENING 0x01 /* Q_QUOTAON in progress */
#define QTF_CLOSING 0x02 /* Q_QUOTAOFF in progress */
/* Convert mount ptr to ulfsmount ptr. */
#define VFSTOULFS(mp) ((struct ulfsmount *)((mp)->mnt_data))
/*
* Macros to access file system parameters (no longer) in the
* ulfsmount structure.
* Used by ulfs_bmap.
*/
#define MNINDIR(lfs) ((lfs)->um_nindir)
#define blkptrtodb(lfs, b) ((b) << (lfs)->um_bptrtodb)
/*
* Predicate for byte-swapping support.
*/
#define FSFMT(vp) (((vp)->v_mount->mnt_iflag & IMNT_DTYPE) == 0)
#endif /* _KERNEL */
#endif /* !_UFS_LFS_ULFSMOUNT_H_ */
+3 -5
View File
@@ -1,4 +1,4 @@
/* $NetBSD: mfs_vfsops.c,v 1.103 2011/06/12 03:36:01 rmind Exp $ */
/* $NetBSD: mfs_vfsops.c,v 1.104 2013/11/23 13:35:37 christos Exp $ */
/*
* Copyright (c) 1989, 1990, 1993, 1994
@@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: mfs_vfsops.c,v 1.103 2011/06/12 03:36:01 rmind Exp $");
__KERNEL_RCSID(0, "$NetBSD: mfs_vfsops.c,v 1.104 2013/11/23 13:35:37 christos Exp $");
#if defined(_KERNEL_OPT)
#include "opt_compat_netbsd.h"
@@ -227,9 +227,7 @@ mfs_mountroot(void)
kmem_free(mfsp, sizeof(*mfsp));
return (error);
}
mutex_enter(&mountlist_lock);
CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
mutex_exit(&mountlist_lock);
mountlist_append(mp);
mp->mnt_vnodecovered = NULLVP;
ump = VFSTOUFS(mp);
fs = ump->um_fs;
+19 -23
View File
@@ -1,4 +1,4 @@
/* $NetBSD: dinode.h,v 1.21 2009/06/28 09:26:18 ad Exp $ */
/* $NetBSD: dinode.h,v 1.24 2013/06/09 17:55:46 dholland Exp $ */
/*
* Copyright (c) 2002 Networks Associates Technology, Inc.
@@ -58,15 +58,15 @@
* the root inode is 2. (Inode 1 is no longer used for this purpose, however
* numerous dump tapes make this assumption, so we are stuck with it).
*/
#define ROOTINO ((ino_t)2)
#define UFS_ROOTINO ((ino_t)2)
/*
* The Whiteout inode# is a dummy non-zero inode number which will
* never be allocated to a real file. It is used as a place holder
* in the directory entry which has been tagged as a DT_W entry.
* See the comments about ROOTINO above.
* See the comments about UFS_ROOTINO above.
*/
#define WINO ((ino_t)1)
#define UFS_WINO ((ino_t)1)
/*
* A dinode contains all the meta-data associated with a UFS file.
@@ -75,17 +75,14 @@
* are defined by types with precise widths.
*/
#define NXADDR 2
#define NDADDR 12 /* Direct addresses in inode. */
#define NIADDR 3 /* Indirect addresses in inode. */
#define UFS_NXADDR 2
#define UFS_NDADDR 12 /* Direct addresses in inode. */
#define UFS_NIADDR 3 /* Indirect addresses in inode. */
struct ufs1_dinode {
u_int16_t di_mode; /* 0: IFMT, permissions; see below. */
int16_t di_nlink; /* 2: File link count. */
union {
u_int16_t oldids[2]; /* 4: Ffs: old user and group ids. */
u_int32_t inumber; /* 4: Lfs: inode number. */
} di_u;
u_int16_t di_oldids[2]; /* 4: Ffs: old user and group ids. */
u_int64_t di_size; /* 8: File byte count. */
int32_t di_atime; /* 16: Last access time. */
int32_t di_atimensec; /* 20: Last access time. */
@@ -93,8 +90,8 @@ struct ufs1_dinode {
int32_t di_mtimensec; /* 28: Last modified time. */
int32_t di_ctime; /* 32: Last inode change time. */
int32_t di_ctimensec; /* 36: Last inode change time. */
int32_t di_db[NDADDR]; /* 40: Direct disk blocks. */
int32_t di_ib[NIADDR]; /* 88: Indirect disk blocks. */
int32_t di_db[UFS_NDADDR]; /* 40: Direct disk blocks. */
int32_t di_ib[UFS_NIADDR]; /* 88: Indirect disk blocks. */
u_int32_t di_flags; /* 100: Status flags (chflags). */
u_int32_t di_blocks; /* 104: Blocks actually held. */
int32_t di_gen; /* 108: Generation number. */
@@ -123,9 +120,9 @@ struct ufs2_dinode {
u_int32_t di_kernflags; /* 84: Kernel flags. */
u_int32_t di_flags; /* 88: Status flags (chflags). */
int32_t di_extsize; /* 92: External attributes block. */
int64_t di_extb[NXADDR];/* 96: External attributes block. */
int64_t di_db[NDADDR]; /* 112: Direct disk blocks. */
int64_t di_ib[NIADDR]; /* 208: Indirect disk blocks. */
int64_t di_extb[UFS_NXADDR];/* 96: External attributes block. */
int64_t di_db[UFS_NDADDR]; /* 112: Direct disk blocks. */
int64_t di_ib[UFS_NIADDR]; /* 208: Indirect disk blocks. */
u_int64_t di_modrev; /* 232: i_modrev for NFSv4 */
int64_t di_spare[2]; /* 240: Reserved; currently unused */
};
@@ -137,16 +134,15 @@ struct ufs2_dinode {
* dev_t value. Short symbolic links place their path in the
* di_db area.
*/
#define di_inumber di_u.inumber
#define di_ogid di_u.oldids[1]
#define di_ouid di_u.oldids[0]
#define di_ogid di_oldids[1]
#define di_ouid di_oldids[0]
#define di_rdev di_db[0]
#define MAXSYMLINKLEN_UFS1 ((NDADDR + NIADDR) * sizeof(int32_t))
#define MAXSYMLINKLEN_UFS2 ((NDADDR + NIADDR) * sizeof(int64_t))
#define UFS1_MAXSYMLINKLEN ((UFS_NDADDR + UFS_NIADDR) * sizeof(int32_t))
#define UFS2_MAXSYMLINKLEN ((UFS_NDADDR + UFS_NIADDR) * sizeof(int64_t))
#define MAXSYMLINKLEN(ip) \
#define UFS_MAXSYMLINKLEN(ip) \
((ip)->i_ump->um_fstype == UFS1) ? \
MAXSYMLINKLEN_UFS1 : MAXSYMLINKLEN_UFS2
UFS1_MAXSYMLINKLEN : UFS2_MAXSYMLINKLEN
/* NeXT used to keep short symlinks in the inode even when using
* FS_42INODEFMT. In that case fs->fs_maxsymlinklen is probably -1,

Some files were not shown because too many files have changed in this diff Show More