ocfs2: Add a name indexed b-tree to directory inodes
This patch makes use of Ocfs2's flexible btree code to add an additional tree to directory inodes. The new tree stores an array of small, fixed-length records in each leaf block. Each record stores a hash value, and pointer to a block in the traditional (unindexed) directory tree where a dirent with the given name hash resides. Lookup exclusively uses this tree to find dirents, thus providing us with constant time name lookups. Some of the hashing code was copied from ext3. Unfortunately, it has lots of unfixed checkpatch errors. I left that as-is so that tracking changes would be easier. Signed-off-by: Mark Fasheh <mfasheh@suse.com> Acked-by: Joel Becker <joel.becker@oracle.com>
This commit is contained in:
parent
4a12ca3a00
commit
9b7895efac
|
@ -294,6 +294,55 @@ static struct ocfs2_extent_tree_operations ocfs2_xattr_tree_et_ops = {
|
|||
.eo_fill_max_leaf_clusters = ocfs2_xattr_tree_fill_max_leaf_clusters,
|
||||
};
|
||||
|
||||
static void ocfs2_dx_root_set_last_eb_blk(struct ocfs2_extent_tree *et,
|
||||
u64 blkno)
|
||||
{
|
||||
struct ocfs2_dx_root_block *dx_root = et->et_object;
|
||||
|
||||
dx_root->dr_last_eb_blk = cpu_to_le64(blkno);
|
||||
}
|
||||
|
||||
static u64 ocfs2_dx_root_get_last_eb_blk(struct ocfs2_extent_tree *et)
|
||||
{
|
||||
struct ocfs2_dx_root_block *dx_root = et->et_object;
|
||||
|
||||
return le64_to_cpu(dx_root->dr_last_eb_blk);
|
||||
}
|
||||
|
||||
static void ocfs2_dx_root_update_clusters(struct inode *inode,
|
||||
struct ocfs2_extent_tree *et,
|
||||
u32 clusters)
|
||||
{
|
||||
struct ocfs2_dx_root_block *dx_root = et->et_object;
|
||||
|
||||
le32_add_cpu(&dx_root->dr_clusters, clusters);
|
||||
}
|
||||
|
||||
static int ocfs2_dx_root_sanity_check(struct inode *inode,
|
||||
struct ocfs2_extent_tree *et)
|
||||
{
|
||||
struct ocfs2_dx_root_block *dx_root = et->et_object;
|
||||
|
||||
BUG_ON(!OCFS2_IS_VALID_DX_ROOT(dx_root));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ocfs2_dx_root_fill_root_el(struct ocfs2_extent_tree *et)
|
||||
{
|
||||
struct ocfs2_dx_root_block *dx_root = et->et_object;
|
||||
|
||||
et->et_root_el = &dx_root->dr_list;
|
||||
}
|
||||
|
||||
static struct ocfs2_extent_tree_operations ocfs2_dx_root_et_ops = {
|
||||
.eo_set_last_eb_blk = ocfs2_dx_root_set_last_eb_blk,
|
||||
.eo_get_last_eb_blk = ocfs2_dx_root_get_last_eb_blk,
|
||||
.eo_update_clusters = ocfs2_dx_root_update_clusters,
|
||||
.eo_sanity_check = ocfs2_dx_root_sanity_check,
|
||||
.eo_fill_root_el = ocfs2_dx_root_fill_root_el,
|
||||
};
|
||||
|
||||
static void __ocfs2_init_extent_tree(struct ocfs2_extent_tree *et,
|
||||
struct inode *inode,
|
||||
struct buffer_head *bh,
|
||||
|
@ -339,6 +388,14 @@ void ocfs2_init_xattr_value_extent_tree(struct ocfs2_extent_tree *et,
|
|||
&ocfs2_xattr_value_et_ops);
|
||||
}
|
||||
|
||||
void ocfs2_init_dx_root_extent_tree(struct ocfs2_extent_tree *et,
|
||||
struct inode *inode,
|
||||
struct buffer_head *bh)
|
||||
{
|
||||
__ocfs2_init_extent_tree(et, inode, bh, ocfs2_journal_access_dr,
|
||||
NULL, &ocfs2_dx_root_et_ops);
|
||||
}
|
||||
|
||||
static inline void ocfs2_et_set_last_eb_blk(struct ocfs2_extent_tree *et,
|
||||
u64 new_last_eb_blk)
|
||||
{
|
||||
|
|
|
@ -75,6 +75,9 @@ struct ocfs2_xattr_value_buf;
|
|||
void ocfs2_init_xattr_value_extent_tree(struct ocfs2_extent_tree *et,
|
||||
struct inode *inode,
|
||||
struct ocfs2_xattr_value_buf *vb);
|
||||
void ocfs2_init_dx_root_extent_tree(struct ocfs2_extent_tree *et,
|
||||
struct inode *inode,
|
||||
struct buffer_head *bh);
|
||||
|
||||
/*
|
||||
* Read an extent block into *bh. If *bh is NULL, a bh will be
|
||||
|
|
1908
fs/ocfs2/dir.c
1908
fs/ocfs2/dir.c
File diff suppressed because it is too large
Load Diff
|
@ -26,9 +26,21 @@
|
|||
#ifndef OCFS2_DIR_H
|
||||
#define OCFS2_DIR_H
|
||||
|
||||
struct ocfs2_dx_hinfo {
|
||||
u32 major_hash;
|
||||
u32 minor_hash;
|
||||
};
|
||||
|
||||
struct ocfs2_dir_lookup_result {
|
||||
struct buffer_head *dl_leaf_bh;
|
||||
struct ocfs2_dir_entry *dl_entry;
|
||||
struct buffer_head *dl_leaf_bh; /* Unindexed leaf
|
||||
* block */
|
||||
struct ocfs2_dir_entry *dl_entry; /* Target dirent in
|
||||
* unindexed leaf */
|
||||
|
||||
struct buffer_head *dl_dx_leaf_bh; /* Indexed leaf block */
|
||||
struct ocfs2_dx_entry *dl_dx_entry; /* Target dx_entry in
|
||||
* indexed leaf */
|
||||
struct ocfs2_dx_hinfo dl_hinfo; /* Name hash results */
|
||||
};
|
||||
void ocfs2_free_dir_lookup_result(struct ocfs2_dir_lookup_result *res);
|
||||
|
||||
|
@ -85,7 +97,10 @@ int ocfs2_fill_new_dir(struct ocfs2_super *osb,
|
|||
struct inode *parent,
|
||||
struct inode *inode,
|
||||
struct buffer_head *fe_bh,
|
||||
struct ocfs2_alloc_context *data_ac);
|
||||
struct ocfs2_alloc_context *data_ac,
|
||||
struct ocfs2_alloc_context *meta_ac);
|
||||
|
||||
int ocfs2_dx_dir_truncate(struct inode *dir, struct buffer_head *di_bh);
|
||||
|
||||
struct ocfs2_dir_block_trailer *ocfs2_dir_trailer_from_size(int blocksize,
|
||||
void *data);
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "ocfs2.h"
|
||||
|
||||
#include "alloc.h"
|
||||
#include "dir.h"
|
||||
#include "blockcheck.h"
|
||||
#include "dlmglue.h"
|
||||
#include "extent_map.h"
|
||||
|
@ -740,6 +741,15 @@ static int ocfs2_wipe_inode(struct inode *inode,
|
|||
goto bail_unlock_dir;
|
||||
}
|
||||
|
||||
/* Remove any dir index tree */
|
||||
if (S_ISDIR(inode->i_mode)) {
|
||||
status = ocfs2_dx_dir_truncate(inode, di_bh);
|
||||
if (status) {
|
||||
mlog_errno(status);
|
||||
goto bail_unlock_dir;
|
||||
}
|
||||
}
|
||||
|
||||
/*Free extended attribute resources associated with this inode.*/
|
||||
status = ocfs2_xattr_remove(inode, di_bh);
|
||||
if (status < 0) {
|
||||
|
|
|
@ -484,6 +484,22 @@ static struct ocfs2_triggers dq_triggers = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct ocfs2_triggers dr_triggers = {
|
||||
.ot_triggers = {
|
||||
.t_commit = ocfs2_commit_trigger,
|
||||
.t_abort = ocfs2_abort_trigger,
|
||||
},
|
||||
.ot_offset = offsetof(struct ocfs2_dx_root_block, dr_check),
|
||||
};
|
||||
|
||||
static struct ocfs2_triggers dl_triggers = {
|
||||
.ot_triggers = {
|
||||
.t_commit = ocfs2_commit_trigger,
|
||||
.t_abort = ocfs2_abort_trigger,
|
||||
},
|
||||
.ot_offset = offsetof(struct ocfs2_dx_leaf, dl_check),
|
||||
};
|
||||
|
||||
static int __ocfs2_journal_access(handle_t *handle,
|
||||
struct inode *inode,
|
||||
struct buffer_head *bh,
|
||||
|
@ -588,6 +604,20 @@ int ocfs2_journal_access_dq(handle_t *handle, struct inode *inode,
|
|||
type);
|
||||
}
|
||||
|
||||
int ocfs2_journal_access_dr(handle_t *handle, struct inode *inode,
|
||||
struct buffer_head *bh, int type)
|
||||
{
|
||||
return __ocfs2_journal_access(handle, inode, bh, &dr_triggers,
|
||||
type);
|
||||
}
|
||||
|
||||
int ocfs2_journal_access_dl(handle_t *handle, struct inode *inode,
|
||||
struct buffer_head *bh, int type)
|
||||
{
|
||||
return __ocfs2_journal_access(handle, inode, bh, &dl_triggers,
|
||||
type);
|
||||
}
|
||||
|
||||
int ocfs2_journal_access(handle_t *handle, struct inode *inode,
|
||||
struct buffer_head *bh, int type)
|
||||
{
|
||||
|
|
|
@ -277,6 +277,12 @@ int ocfs2_journal_access_dq(handle_t *handle, struct inode *inode,
|
|||
/* dirblock */
|
||||
int ocfs2_journal_access_db(handle_t *handle, struct inode *inode,
|
||||
struct buffer_head *bh, int type);
|
||||
/* ocfs2_dx_root_block */
|
||||
int ocfs2_journal_access_dr(handle_t *handle, struct inode *inode,
|
||||
struct buffer_head *bh, int type);
|
||||
/* ocfs2_dx_leaf */
|
||||
int ocfs2_journal_access_dl(handle_t *handle, struct inode *inode,
|
||||
struct buffer_head *bh, int type);
|
||||
/* Anything that has no ecc */
|
||||
int ocfs2_journal_access(handle_t *handle, struct inode *inode,
|
||||
struct buffer_head *bh, int type);
|
||||
|
@ -382,11 +388,26 @@ static inline int ocfs2_remove_extent_credits(struct super_block *sb)
|
|||
* bitmap block for the new bit) */
|
||||
#define OCFS2_DIR_LINK_ADDITIONAL_CREDITS (1 + 2)
|
||||
|
||||
/* parent fe, parent block, new file entry, inode alloc fe, inode alloc
|
||||
* group descriptor + mkdir/symlink blocks + quota update */
|
||||
static inline int ocfs2_mknod_credits(struct super_block *sb)
|
||||
static inline int ocfs2_add_dir_index_credits(struct super_block *sb)
|
||||
{
|
||||
return 3 + OCFS2_SUBALLOC_ALLOC + OCFS2_DIR_LINK_ADDITIONAL_CREDITS +
|
||||
/* 1 block for index, 2 allocs (data, metadata), 1 clusters
|
||||
* worth of blocks for initial extent. */
|
||||
return 1 + 2 * OCFS2_SUBALLOC_ALLOC +
|
||||
ocfs2_clusters_to_blocks(sb, 1);
|
||||
}
|
||||
|
||||
/* parent fe, parent block, new file entry, index leaf, inode alloc fe, inode
|
||||
* alloc group descriptor + mkdir/symlink blocks + dir blocks + xattr
|
||||
* blocks + quota update */
|
||||
static inline int ocfs2_mknod_credits(struct super_block *sb, int is_dir,
|
||||
int xattr_credits)
|
||||
{
|
||||
int dir_credits = OCFS2_DIR_LINK_ADDITIONAL_CREDITS;
|
||||
|
||||
if (is_dir)
|
||||
dir_credits += ocfs2_add_dir_index_credits(sb);
|
||||
|
||||
return 4 + OCFS2_SUBALLOC_ALLOC + dir_credits + xattr_credits +
|
||||
ocfs2_quota_trans_credits(sb);
|
||||
}
|
||||
|
||||
|
@ -399,31 +420,31 @@ static inline int ocfs2_mknod_credits(struct super_block *sb)
|
|||
#define OCFS2_SIMPLE_DIR_EXTEND_CREDITS (2)
|
||||
|
||||
/* file update (nlink, etc) + directory mtime/ctime + dir entry block + quota
|
||||
* update on dir */
|
||||
* update on dir + index leaf */
|
||||
static inline int ocfs2_link_credits(struct super_block *sb)
|
||||
{
|
||||
return 2*OCFS2_INODE_UPDATE_CREDITS + 1 +
|
||||
return 2*OCFS2_INODE_UPDATE_CREDITS + 2 +
|
||||
ocfs2_quota_trans_credits(sb);
|
||||
}
|
||||
|
||||
/* inode + dir inode (if we unlink a dir), + dir entry block + orphan
|
||||
* dir inode link */
|
||||
* dir inode link + dir inode index leaf */
|
||||
static inline int ocfs2_unlink_credits(struct super_block *sb)
|
||||
{
|
||||
/* The quota update from ocfs2_link_credits is unused here... */
|
||||
return 2 * OCFS2_INODE_UPDATE_CREDITS + 1 + ocfs2_link_credits(sb);
|
||||
return 2 * OCFS2_INODE_UPDATE_CREDITS + 2 + ocfs2_link_credits(sb);
|
||||
}
|
||||
|
||||
/* dinode + orphan dir dinode + inode alloc dinode + orphan dir entry +
|
||||
* inode alloc group descriptor */
|
||||
#define OCFS2_DELETE_INODE_CREDITS (3 * OCFS2_INODE_UPDATE_CREDITS + 1 + 1)
|
||||
* inode alloc group descriptor + orphan dir index leaf */
|
||||
#define OCFS2_DELETE_INODE_CREDITS (3 * OCFS2_INODE_UPDATE_CREDITS + 3)
|
||||
|
||||
/* dinode update, old dir dinode update, new dir dinode update, old
|
||||
* dir dir entry, new dir dir entry, dir entry update for renaming
|
||||
* directory + target unlink */
|
||||
* directory + target unlink + 3 x dir index leaves */
|
||||
static inline int ocfs2_rename_credits(struct super_block *sb)
|
||||
{
|
||||
return 3 * OCFS2_INODE_UPDATE_CREDITS + 3 + ocfs2_unlink_credits(sb);
|
||||
return 3 * OCFS2_INODE_UPDATE_CREDITS + 6 + ocfs2_unlink_credits(sb);
|
||||
}
|
||||
|
||||
/* global bitmap dinode, group desc., relinked group,
|
||||
|
@ -433,6 +454,10 @@ static inline int ocfs2_rename_credits(struct super_block *sb)
|
|||
+ OCFS2_INODE_UPDATE_CREDITS \
|
||||
+ OCFS2_XATTR_BLOCK_UPDATE_CREDITS)
|
||||
|
||||
/* inode update, removal of dx root block from allocator */
|
||||
#define OCFS2_DX_ROOT_REMOVE_CREDITS (OCFS2_INODE_UPDATE_CREDITS + \
|
||||
OCFS2_SUBALLOC_FREE)
|
||||
|
||||
/*
|
||||
* Please note that the caller must make sure that root_el is the root
|
||||
* of extent tree. So for an inode, it should be &fe->id2.i_list. Otherwise
|
||||
|
@ -468,7 +493,7 @@ static inline int ocfs2_calc_extend_credits(struct super_block *sb,
|
|||
|
||||
static inline int ocfs2_calc_symlink_credits(struct super_block *sb)
|
||||
{
|
||||
int blocks = ocfs2_mknod_credits(sb);
|
||||
int blocks = ocfs2_mknod_credits(sb, 0, 0);
|
||||
|
||||
/* links can be longer than one block so we may update many
|
||||
* within our single allocated extent. */
|
||||
|
|
|
@ -231,8 +231,9 @@ static int ocfs2_mknod(struct inode *dir,
|
|||
struct inode *inode = NULL;
|
||||
struct ocfs2_alloc_context *inode_ac = NULL;
|
||||
struct ocfs2_alloc_context *data_ac = NULL;
|
||||
struct ocfs2_alloc_context *xattr_ac = NULL;
|
||||
struct ocfs2_alloc_context *meta_ac = NULL;
|
||||
int want_clusters = 0;
|
||||
int want_meta = 0;
|
||||
int xattr_credits = 0;
|
||||
struct ocfs2_security_xattr_info si = {
|
||||
.enable = 1,
|
||||
|
@ -309,16 +310,30 @@ static int ocfs2_mknod(struct inode *dir,
|
|||
/* calculate meta data/clusters for setting security and acl xattr */
|
||||
status = ocfs2_calc_xattr_init(dir, parent_fe_bh, mode,
|
||||
&si, &want_clusters,
|
||||
&xattr_credits, &xattr_ac);
|
||||
&xattr_credits, &want_meta);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Reserve a cluster if creating an extent based directory. */
|
||||
if (S_ISDIR(mode) && !ocfs2_supports_inline_data(osb))
|
||||
if (S_ISDIR(mode) && !ocfs2_supports_inline_data(osb)) {
|
||||
want_clusters += 1;
|
||||
|
||||
/* Dir indexing requires extra space as well */
|
||||
if (ocfs2_supports_indexed_dirs(osb)) {
|
||||
want_clusters++;
|
||||
want_meta++;
|
||||
}
|
||||
}
|
||||
|
||||
status = ocfs2_reserve_new_metadata_blocks(osb, want_meta, &meta_ac);
|
||||
if (status < 0) {
|
||||
if (status != -ENOSPC)
|
||||
mlog_errno(status);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
status = ocfs2_reserve_clusters(osb, want_clusters, &data_ac);
|
||||
if (status < 0) {
|
||||
if (status != -ENOSPC)
|
||||
|
@ -326,8 +341,9 @@ static int ocfs2_mknod(struct inode *dir,
|
|||
goto leave;
|
||||
}
|
||||
|
||||
handle = ocfs2_start_trans(osb, ocfs2_mknod_credits(osb->sb) +
|
||||
xattr_credits);
|
||||
handle = ocfs2_start_trans(osb, ocfs2_mknod_credits(osb->sb,
|
||||
S_ISDIR(mode),
|
||||
xattr_credits));
|
||||
if (IS_ERR(handle)) {
|
||||
status = PTR_ERR(handle);
|
||||
handle = NULL;
|
||||
|
@ -355,7 +371,7 @@ static int ocfs2_mknod(struct inode *dir,
|
|||
|
||||
if (S_ISDIR(mode)) {
|
||||
status = ocfs2_fill_new_dir(osb, handle, dir, inode,
|
||||
new_fe_bh, data_ac);
|
||||
new_fe_bh, data_ac, meta_ac);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
goto leave;
|
||||
|
@ -377,7 +393,7 @@ static int ocfs2_mknod(struct inode *dir,
|
|||
}
|
||||
|
||||
status = ocfs2_init_acl(handle, inode, dir, new_fe_bh, parent_fe_bh,
|
||||
xattr_ac, data_ac);
|
||||
meta_ac, data_ac);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
goto leave;
|
||||
|
@ -385,7 +401,7 @@ static int ocfs2_mknod(struct inode *dir,
|
|||
|
||||
if (si.enable) {
|
||||
status = ocfs2_init_security_set(handle, inode, new_fe_bh, &si,
|
||||
xattr_ac, data_ac);
|
||||
meta_ac, data_ac);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
goto leave;
|
||||
|
@ -440,8 +456,8 @@ leave:
|
|||
if (data_ac)
|
||||
ocfs2_free_alloc_context(data_ac);
|
||||
|
||||
if (xattr_ac)
|
||||
ocfs2_free_alloc_context(xattr_ac);
|
||||
if (meta_ac)
|
||||
ocfs2_free_alloc_context(meta_ac);
|
||||
|
||||
mlog_exit(status);
|
||||
|
||||
|
@ -463,6 +479,7 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb,
|
|||
struct ocfs2_extent_list *fel;
|
||||
u64 fe_blkno = 0;
|
||||
u16 suballoc_bit;
|
||||
u16 feat;
|
||||
|
||||
mlog_entry("(0x%p, 0x%p, %d, %lu, '%.*s')\n", dir, dentry,
|
||||
inode->i_mode, (unsigned long)dev, dentry->d_name.len,
|
||||
|
@ -526,11 +543,11 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb,
|
|||
fe->i_dtime = 0;
|
||||
|
||||
/*
|
||||
* If supported, directories start with inline data.
|
||||
* If supported, directories start with inline data. If inline
|
||||
* isn't supported, but indexing is, we start them as indexed.
|
||||
*/
|
||||
feat = le16_to_cpu(fe->i_dyn_features);
|
||||
if (S_ISDIR(inode->i_mode) && ocfs2_supports_inline_data(osb)) {
|
||||
u16 feat = le16_to_cpu(fe->i_dyn_features);
|
||||
|
||||
fe->i_dyn_features = cpu_to_le16(feat | OCFS2_INLINE_DATA_FL);
|
||||
|
||||
fe->id2.i_data.id_count = cpu_to_le16(
|
||||
|
|
|
@ -340,6 +340,9 @@ struct ocfs2_super
|
|||
|
||||
/* used to protect metaecc calculation check of xattr. */
|
||||
spinlock_t osb_xattr_lock;
|
||||
|
||||
unsigned int osb_dx_mask;
|
||||
u32 osb_dx_seed[4];
|
||||
};
|
||||
|
||||
#define OCFS2_SB(sb) ((struct ocfs2_super *)(sb)->s_fs_info)
|
||||
|
@ -398,6 +401,13 @@ static inline int ocfs2_meta_ecc(struct ocfs2_super *osb)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int ocfs2_supports_indexed_dirs(struct ocfs2_super *osb)
|
||||
{
|
||||
if (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_INDEXED_DIRS)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* set / clear functions because cluster events can make these happen
|
||||
* in parallel so we want the transitions to be atomic. this also
|
||||
* means that any future flags osb_flags must be protected by spinlock
|
||||
|
@ -478,6 +488,12 @@ static inline int ocfs2_uses_extended_slot_map(struct ocfs2_super *osb)
|
|||
#define OCFS2_IS_VALID_DIR_TRAILER(ptr) \
|
||||
(!strcmp((ptr)->db_signature, OCFS2_DIR_TRAILER_SIGNATURE))
|
||||
|
||||
#define OCFS2_IS_VALID_DX_ROOT(ptr) \
|
||||
(!strcmp((ptr)->dr_signature, OCFS2_DX_ROOT_SIGNATURE))
|
||||
|
||||
#define OCFS2_IS_VALID_DX_LEAF(ptr) \
|
||||
(!strcmp((ptr)->dl_signature, OCFS2_DX_LEAF_SIGNATURE))
|
||||
|
||||
static inline unsigned long ino_from_blkno(struct super_block *sb,
|
||||
u64 blkno)
|
||||
{
|
||||
|
|
|
@ -66,6 +66,8 @@
|
|||
#define OCFS2_GROUP_DESC_SIGNATURE "GROUP01"
|
||||
#define OCFS2_XATTR_BLOCK_SIGNATURE "XATTR01"
|
||||
#define OCFS2_DIR_TRAILER_SIGNATURE "DIRTRL1"
|
||||
#define OCFS2_DX_ROOT_SIGNATURE "DXDIR01"
|
||||
#define OCFS2_DX_LEAF_SIGNATURE "DXLEAF1"
|
||||
|
||||
/* Compatibility flags */
|
||||
#define OCFS2_HAS_COMPAT_FEATURE(sb,mask) \
|
||||
|
@ -151,6 +153,9 @@
|
|||
/* Support for extended attributes */
|
||||
#define OCFS2_FEATURE_INCOMPAT_XATTR 0x0200
|
||||
|
||||
/* Support for indexed directores */
|
||||
#define OCFS2_FEATURE_INCOMPAT_INDEXED_DIRS 0x0400
|
||||
|
||||
/* Metadata checksum and error correction */
|
||||
#define OCFS2_FEATURE_INCOMPAT_META_ECC 0x0800
|
||||
|
||||
|
@ -628,8 +633,9 @@ struct ocfs2_super_block {
|
|||
/*B8*/ __le16 s_xattr_inline_size; /* extended attribute inline size
|
||||
for this fs*/
|
||||
__le16 s_reserved0;
|
||||
__le32 s_reserved1;
|
||||
/*C0*/ __le64 s_reserved2[16]; /* Fill out superblock */
|
||||
__le32 s_dx_seed[3]; /* seed[0-2] for dx dir hash.
|
||||
* s_uuid_hash serves as seed[3]. */
|
||||
/*C0*/ __le64 s_reserved2[15]; /* Fill out superblock */
|
||||
/*140*/
|
||||
|
||||
/*
|
||||
|
@ -705,7 +711,8 @@ struct ocfs2_dinode {
|
|||
__le16 i_dyn_features;
|
||||
__le64 i_xattr_loc;
|
||||
/*80*/ struct ocfs2_block_check i_check; /* Error checking */
|
||||
/*88*/ __le64 i_reserved2[6];
|
||||
/*88*/ __le64 i_dx_root; /* Pointer to dir index root block */
|
||||
__le64 i_reserved2[5];
|
||||
/*B8*/ union {
|
||||
__le64 i_pad1; /* Generic way to refer to this
|
||||
64bit union */
|
||||
|
@ -781,6 +788,75 @@ struct ocfs2_dir_block_trailer {
|
|||
/*40*/
|
||||
};
|
||||
|
||||
/*
|
||||
* A directory entry in the indexed tree. We don't store the full name here,
|
||||
* but instead provide a pointer to the full dirent in the unindexed tree.
|
||||
*
|
||||
* We also store name_len here so as to reduce the number of leaf blocks we
|
||||
* need to search in case of collisions.
|
||||
*/
|
||||
struct ocfs2_dx_entry {
|
||||
__le32 dx_major_hash; /* Used to find logical
|
||||
* cluster in index */
|
||||
__le32 dx_minor_hash; /* Lower bits used to find
|
||||
* block in cluster */
|
||||
__le64 dx_dirent_blk; /* Physical block in unindexed
|
||||
* tree holding this dirent. */
|
||||
};
|
||||
|
||||
struct ocfs2_dx_entry_list {
|
||||
__le32 de_reserved;
|
||||
__le16 de_count; /* Maximum number of entries
|
||||
* possible in de_entries */
|
||||
__le16 de_num_used; /* Current number of
|
||||
* de_entries entries */
|
||||
struct ocfs2_dx_entry de_entries[0]; /* Indexed dir entries
|
||||
* in a packed array of
|
||||
* length de_num_used */
|
||||
};
|
||||
|
||||
/*
|
||||
* A directory indexing block. Each indexed directory has one of these,
|
||||
* pointed to by ocfs2_dinode.
|
||||
*
|
||||
* This block stores an indexed btree root, and a set of free space
|
||||
* start-of-list pointers.
|
||||
*/
|
||||
struct ocfs2_dx_root_block {
|
||||
__u8 dr_signature[8]; /* Signature for verification */
|
||||
struct ocfs2_block_check dr_check; /* Error checking */
|
||||
__le16 dr_suballoc_slot; /* Slot suballocator this
|
||||
* block belongs to. */
|
||||
__le16 dr_suballoc_bit; /* Bit offset in suballocator
|
||||
* block group */
|
||||
__le32 dr_fs_generation; /* Must match super block */
|
||||
__le64 dr_blkno; /* Offset on disk, in blocks */
|
||||
__le64 dr_last_eb_blk; /* Pointer to last
|
||||
* extent block */
|
||||
__le32 dr_clusters; /* Clusters allocated
|
||||
* to the indexed tree. */
|
||||
__le32 dr_reserved1;
|
||||
__le64 dr_dir_blkno; /* Pointer to parent inode */
|
||||
__le64 dr_reserved2;
|
||||
__le64 dr_reserved3[16];
|
||||
struct ocfs2_extent_list dr_list; /* Keep this aligned to 128
|
||||
* bits for maximum space
|
||||
* efficiency. */
|
||||
};
|
||||
|
||||
/*
|
||||
* The header of a leaf block in the indexed tree.
|
||||
*/
|
||||
struct ocfs2_dx_leaf {
|
||||
__u8 dl_signature[8];/* Signature for verification */
|
||||
struct ocfs2_block_check dl_check; /* Error checking */
|
||||
__le64 dl_blkno; /* Offset on disk, in blocks */
|
||||
__le32 dl_fs_generation;/* Must match super block */
|
||||
__le32 dl_reserved0;
|
||||
__le64 dl_reserved1;
|
||||
struct ocfs2_dx_entry_list dl_list;
|
||||
};
|
||||
|
||||
/*
|
||||
* On disk allocator group structure for OCFS2
|
||||
*/
|
||||
|
@ -1112,6 +1188,16 @@ static inline int ocfs2_extent_recs_per_inode_with_xattr(
|
|||
return size / sizeof(struct ocfs2_extent_rec);
|
||||
}
|
||||
|
||||
static inline int ocfs2_extent_recs_per_dx_root(struct super_block *sb)
|
||||
{
|
||||
int size;
|
||||
|
||||
size = sb->s_blocksize -
|
||||
offsetof(struct ocfs2_dx_root_block, dr_list.l_recs);
|
||||
|
||||
return size / sizeof(struct ocfs2_extent_rec);
|
||||
}
|
||||
|
||||
static inline int ocfs2_chain_recs_per_inode(struct super_block *sb)
|
||||
{
|
||||
int size;
|
||||
|
@ -1132,6 +1218,16 @@ static inline u16 ocfs2_extent_recs_per_eb(struct super_block *sb)
|
|||
return size / sizeof(struct ocfs2_extent_rec);
|
||||
}
|
||||
|
||||
static inline int ocfs2_dx_entries_per_leaf(struct super_block *sb)
|
||||
{
|
||||
int size;
|
||||
|
||||
size = sb->s_blocksize -
|
||||
offsetof(struct ocfs2_dx_leaf, dl_list.de_entries);
|
||||
|
||||
return size / sizeof(struct ocfs2_dx_entry);
|
||||
}
|
||||
|
||||
static inline u16 ocfs2_local_alloc_size(struct super_block *sb)
|
||||
{
|
||||
u16 size;
|
||||
|
|
|
@ -1918,6 +1918,12 @@ static int ocfs2_initialize_super(struct super_block *sb,
|
|||
bbits = le32_to_cpu(di->id2.i_super.s_blocksize_bits);
|
||||
sb->s_maxbytes = ocfs2_max_file_offset(bbits, cbits);
|
||||
|
||||
osb->osb_dx_mask = (1 << (cbits - bbits)) - 1;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
osb->osb_dx_seed[i] = le32_to_cpu(di->id2.i_super.s_dx_seed[i]);
|
||||
osb->osb_dx_seed[3] = le32_to_cpu(di->id2.i_super.s_uuid_hash);
|
||||
|
||||
osb->sb = sb;
|
||||
/* Save off for ocfs2_rw_direct */
|
||||
osb->s_sectsize_bits = blksize_bits(sector_size);
|
||||
|
|
|
@ -512,7 +512,7 @@ int ocfs2_calc_xattr_init(struct inode *dir,
|
|||
struct ocfs2_security_xattr_info *si,
|
||||
int *want_clusters,
|
||||
int *xattr_credits,
|
||||
struct ocfs2_alloc_context **xattr_ac)
|
||||
int *want_meta)
|
||||
{
|
||||
int ret = 0;
|
||||
struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
|
||||
|
@ -554,11 +554,7 @@ int ocfs2_calc_xattr_init(struct inode *dir,
|
|||
if (dir->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE ||
|
||||
(S_ISDIR(mode) && ocfs2_supports_inline_data(osb)) ||
|
||||
(s_size + a_size) > OCFS2_XATTR_FREE_IN_IBODY) {
|
||||
ret = ocfs2_reserve_new_metadata_blocks(osb, 1, xattr_ac);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
return ret;
|
||||
}
|
||||
*want_meta = *want_meta + 1;
|
||||
*xattr_credits += OCFS2_XATTR_BLOCK_CREATE_CREDITS;
|
||||
}
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ int ocfs2_calc_security_init(struct inode *,
|
|||
int *, int *, struct ocfs2_alloc_context **);
|
||||
int ocfs2_calc_xattr_init(struct inode *, struct buffer_head *,
|
||||
int, struct ocfs2_security_xattr_info *,
|
||||
int *, int *, struct ocfs2_alloc_context **);
|
||||
int *, int *, int *);
|
||||
|
||||
/*
|
||||
* xattrs can live inside an inode, as part of an external xattr block,
|
||||
|
|
Loading…
Reference in New Issue