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:
+200
-199
@@ -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__ */
|
||||
|
||||
@@ -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
@@ -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 -
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
/*
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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_ */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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_ */
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+504
-327
File diff suppressed because it is too large
Load Diff
@@ -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 = #
|
||||
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);
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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
@@ -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
@@ -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_ */
|
||||
@@ -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_ */
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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 *);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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
@@ -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_ */
|
||||
@@ -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
@@ -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
Reference in New Issue
Block a user