mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-13 11:51:32 +00:00
Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jlbec/ocfs2
* 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jlbec/ocfs2: (85 commits) ocfs2: Use buffer IO if we are appending a file. ocfs2: add spinlock protection when dealing with lockres->purge. dlmglue.c: add missed mlog lines ocfs2: __ocfs2_abort() should not enable panic for local mounts ocfs2: Add ioctl for reflink. ocfs2: Enable refcount tree support. ocfs2: Implement ocfs2_reflink. ocfs2: Add preserve to reflink. ocfs2: Create reflinked file in orphan dir. ocfs2: Use proper parameter for some inode operation. ocfs2: Make transaction extend more efficient. ocfs2: Don't merge in 1st refcount ops of reflink. ocfs2: Modify removing xattr process for refcount. ocfs2: Add reflink support for xattr. ocfs2: Create an xattr indexed block if needed. ocfs2: Call refcount tree remove process properly. ocfs2: Attach xattr clusters to refcount tree. ocfs2: Abstract ocfs2 xattr tree extend rec iteration process. ocfs2: Abstract the creation of xattr block. ocfs2: Remove inode from ocfs2_xattr_bucket_get_name_value. ...
This commit is contained in:
commit
b64ada6b23
@ -28,6 +28,7 @@ ocfs2-objs := \
|
||||
locks.o \
|
||||
mmap.o \
|
||||
namei.o \
|
||||
refcounttree.o \
|
||||
resize.o \
|
||||
slot_map.o \
|
||||
suballoc.o \
|
||||
|
1358
fs/ocfs2/alloc.c
1358
fs/ocfs2/alloc.c
File diff suppressed because it is too large
Load Diff
101
fs/ocfs2/alloc.h
101
fs/ocfs2/alloc.h
@ -45,7 +45,8 @@
|
||||
*
|
||||
* ocfs2_extent_tree contains info for the root of the b-tree, it must have a
|
||||
* root ocfs2_extent_list and a root_bh so that they can be used in the b-tree
|
||||
* functions. With metadata ecc, we now call different journal_access
|
||||
* functions. It needs the ocfs2_caching_info structure associated with
|
||||
* I/O on the tree. With metadata ecc, we now call different journal_access
|
||||
* functions for each type of metadata, so it must have the
|
||||
* root_journal_access function.
|
||||
* ocfs2_extent_tree_operations abstract the normal operations we do for
|
||||
@ -56,6 +57,7 @@ struct ocfs2_extent_tree {
|
||||
struct ocfs2_extent_tree_operations *et_ops;
|
||||
struct buffer_head *et_root_bh;
|
||||
struct ocfs2_extent_list *et_root_el;
|
||||
struct ocfs2_caching_info *et_ci;
|
||||
ocfs2_journal_access_func et_root_journal_access;
|
||||
void *et_object;
|
||||
unsigned int et_max_leaf_clusters;
|
||||
@ -66,31 +68,32 @@ struct ocfs2_extent_tree {
|
||||
* specified object buffer.
|
||||
*/
|
||||
void ocfs2_init_dinode_extent_tree(struct ocfs2_extent_tree *et,
|
||||
struct inode *inode,
|
||||
struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh);
|
||||
void ocfs2_init_xattr_tree_extent_tree(struct ocfs2_extent_tree *et,
|
||||
struct inode *inode,
|
||||
struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh);
|
||||
struct ocfs2_xattr_value_buf;
|
||||
void ocfs2_init_xattr_value_extent_tree(struct ocfs2_extent_tree *et,
|
||||
struct inode *inode,
|
||||
struct ocfs2_caching_info *ci,
|
||||
struct ocfs2_xattr_value_buf *vb);
|
||||
void ocfs2_init_dx_root_extent_tree(struct ocfs2_extent_tree *et,
|
||||
struct inode *inode,
|
||||
struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh);
|
||||
void ocfs2_init_refcount_extent_tree(struct ocfs2_extent_tree *et,
|
||||
struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh);
|
||||
|
||||
/*
|
||||
* Read an extent block into *bh. If *bh is NULL, a bh will be
|
||||
* allocated. This is a cached read. The extent block will be validated
|
||||
* with ocfs2_validate_extent_block().
|
||||
*/
|
||||
int ocfs2_read_extent_block(struct inode *inode, u64 eb_blkno,
|
||||
int ocfs2_read_extent_block(struct ocfs2_caching_info *ci, u64 eb_blkno,
|
||||
struct buffer_head **bh);
|
||||
|
||||
struct ocfs2_alloc_context;
|
||||
int ocfs2_insert_extent(struct ocfs2_super *osb,
|
||||
handle_t *handle,
|
||||
struct inode *inode,
|
||||
int ocfs2_insert_extent(handle_t *handle,
|
||||
struct ocfs2_extent_tree *et,
|
||||
u32 cpos,
|
||||
u64 start_blk,
|
||||
@ -103,25 +106,36 @@ enum ocfs2_alloc_restarted {
|
||||
RESTART_TRANS,
|
||||
RESTART_META
|
||||
};
|
||||
int ocfs2_add_clusters_in_btree(struct ocfs2_super *osb,
|
||||
struct inode *inode,
|
||||
int ocfs2_add_clusters_in_btree(handle_t *handle,
|
||||
struct ocfs2_extent_tree *et,
|
||||
u32 *logical_offset,
|
||||
u32 clusters_to_add,
|
||||
int mark_unwritten,
|
||||
struct ocfs2_extent_tree *et,
|
||||
handle_t *handle,
|
||||
struct ocfs2_alloc_context *data_ac,
|
||||
struct ocfs2_alloc_context *meta_ac,
|
||||
enum ocfs2_alloc_restarted *reason_ret);
|
||||
struct ocfs2_cached_dealloc_ctxt;
|
||||
struct ocfs2_path;
|
||||
int ocfs2_split_extent(handle_t *handle,
|
||||
struct ocfs2_extent_tree *et,
|
||||
struct ocfs2_path *path,
|
||||
int split_index,
|
||||
struct ocfs2_extent_rec *split_rec,
|
||||
struct ocfs2_alloc_context *meta_ac,
|
||||
struct ocfs2_cached_dealloc_ctxt *dealloc);
|
||||
int ocfs2_mark_extent_written(struct inode *inode,
|
||||
struct ocfs2_extent_tree *et,
|
||||
handle_t *handle, u32 cpos, u32 len, u32 phys,
|
||||
struct ocfs2_alloc_context *meta_ac,
|
||||
struct ocfs2_cached_dealloc_ctxt *dealloc);
|
||||
int ocfs2_remove_extent(struct inode *inode,
|
||||
struct ocfs2_extent_tree *et,
|
||||
u32 cpos, u32 len, handle_t *handle,
|
||||
int ocfs2_change_extent_flag(handle_t *handle,
|
||||
struct ocfs2_extent_tree *et,
|
||||
u32 cpos, u32 len, u32 phys,
|
||||
struct ocfs2_alloc_context *meta_ac,
|
||||
struct ocfs2_cached_dealloc_ctxt *dealloc,
|
||||
int new_flags, int clear_flags);
|
||||
int ocfs2_remove_extent(handle_t *handle, struct ocfs2_extent_tree *et,
|
||||
u32 cpos, u32 len,
|
||||
struct ocfs2_alloc_context *meta_ac,
|
||||
struct ocfs2_cached_dealloc_ctxt *dealloc);
|
||||
int ocfs2_remove_btree_range(struct inode *inode,
|
||||
@ -130,7 +144,6 @@ int ocfs2_remove_btree_range(struct inode *inode,
|
||||
struct ocfs2_cached_dealloc_ctxt *dealloc);
|
||||
|
||||
int ocfs2_num_free_extents(struct ocfs2_super *osb,
|
||||
struct inode *inode,
|
||||
struct ocfs2_extent_tree *et);
|
||||
|
||||
/*
|
||||
@ -195,6 +208,9 @@ static inline void ocfs2_init_dealloc_ctxt(struct ocfs2_cached_dealloc_ctxt *c)
|
||||
}
|
||||
int ocfs2_cache_cluster_dealloc(struct ocfs2_cached_dealloc_ctxt *ctxt,
|
||||
u64 blkno, unsigned int bit);
|
||||
int ocfs2_cache_block_dealloc(struct ocfs2_cached_dealloc_ctxt *ctxt,
|
||||
int type, int slot, u64 blkno,
|
||||
unsigned int bit);
|
||||
static inline int ocfs2_dealloc_has_cluster(struct ocfs2_cached_dealloc_ctxt *c)
|
||||
{
|
||||
return c->c_global_allocator != NULL;
|
||||
@ -222,8 +238,9 @@ int ocfs2_commit_truncate(struct ocfs2_super *osb,
|
||||
int ocfs2_truncate_inline(struct inode *inode, struct buffer_head *di_bh,
|
||||
unsigned int start, unsigned int end, int trunc);
|
||||
|
||||
int ocfs2_find_leaf(struct inode *inode, struct ocfs2_extent_list *root_el,
|
||||
u32 cpos, struct buffer_head **leaf_bh);
|
||||
int ocfs2_find_leaf(struct ocfs2_caching_info *ci,
|
||||
struct ocfs2_extent_list *root_el, u32 cpos,
|
||||
struct buffer_head **leaf_bh);
|
||||
int ocfs2_search_extent_list(struct ocfs2_extent_list *el, u32 v_cluster);
|
||||
|
||||
/*
|
||||
@ -254,4 +271,50 @@ static inline int ocfs2_is_empty_extent(struct ocfs2_extent_rec *rec)
|
||||
return !rec->e_leaf_clusters;
|
||||
}
|
||||
|
||||
int ocfs2_grab_pages(struct inode *inode, loff_t start, loff_t end,
|
||||
struct page **pages, int *num);
|
||||
void ocfs2_map_and_dirty_page(struct inode *inode, handle_t *handle,
|
||||
unsigned int from, unsigned int to,
|
||||
struct page *page, int zero, u64 *phys);
|
||||
/*
|
||||
* Structures which describe a path through a btree, and functions to
|
||||
* manipulate them.
|
||||
*
|
||||
* The idea here is to be as generic as possible with the tree
|
||||
* manipulation code.
|
||||
*/
|
||||
struct ocfs2_path_item {
|
||||
struct buffer_head *bh;
|
||||
struct ocfs2_extent_list *el;
|
||||
};
|
||||
|
||||
#define OCFS2_MAX_PATH_DEPTH 5
|
||||
|
||||
struct ocfs2_path {
|
||||
int p_tree_depth;
|
||||
ocfs2_journal_access_func p_root_access;
|
||||
struct ocfs2_path_item p_node[OCFS2_MAX_PATH_DEPTH];
|
||||
};
|
||||
|
||||
#define path_root_bh(_path) ((_path)->p_node[0].bh)
|
||||
#define path_root_el(_path) ((_path)->p_node[0].el)
|
||||
#define path_root_access(_path)((_path)->p_root_access)
|
||||
#define path_leaf_bh(_path) ((_path)->p_node[(_path)->p_tree_depth].bh)
|
||||
#define path_leaf_el(_path) ((_path)->p_node[(_path)->p_tree_depth].el)
|
||||
#define path_num_items(_path) ((_path)->p_tree_depth + 1)
|
||||
|
||||
void ocfs2_reinit_path(struct ocfs2_path *path, int keep_root);
|
||||
void ocfs2_free_path(struct ocfs2_path *path);
|
||||
int ocfs2_find_path(struct ocfs2_caching_info *ci,
|
||||
struct ocfs2_path *path,
|
||||
u32 cpos);
|
||||
struct ocfs2_path *ocfs2_new_path_from_path(struct ocfs2_path *path);
|
||||
struct ocfs2_path *ocfs2_new_path_from_et(struct ocfs2_extent_tree *et);
|
||||
int ocfs2_path_bh_journal_access(handle_t *handle,
|
||||
struct ocfs2_caching_info *ci,
|
||||
struct ocfs2_path *path,
|
||||
int idx);
|
||||
int ocfs2_journal_access_path(struct ocfs2_caching_info *ci,
|
||||
handle_t *handle,
|
||||
struct ocfs2_path *path);
|
||||
#endif /* OCFS2_ALLOC_H */
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "suballoc.h"
|
||||
#include "super.h"
|
||||
#include "symlink.h"
|
||||
#include "refcounttree.h"
|
||||
|
||||
#include "buffer_head_io.h"
|
||||
|
||||
@ -126,8 +127,8 @@ bail:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ocfs2_get_block(struct inode *inode, sector_t iblock,
|
||||
struct buffer_head *bh_result, int create)
|
||||
int ocfs2_get_block(struct inode *inode, sector_t iblock,
|
||||
struct buffer_head *bh_result, int create)
|
||||
{
|
||||
int err = 0;
|
||||
unsigned int ext_flags;
|
||||
@ -590,6 +591,8 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock,
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* We should already CoW the refcounted extent. */
|
||||
BUG_ON(ext_flags & OCFS2_EXT_REFCOUNTED);
|
||||
/*
|
||||
* get_more_blocks() expects us to describe a hole by clearing
|
||||
* the mapped bit on bh_result().
|
||||
@ -687,6 +690,10 @@ static ssize_t ocfs2_direct_IO(int rw,
|
||||
if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
|
||||
return 0;
|
||||
|
||||
/* Fallback to buffered I/O if we are appending. */
|
||||
if (i_size_read(inode) <= offset)
|
||||
return 0;
|
||||
|
||||
ret = blockdev_direct_IO_no_locking(rw, iocb, inode,
|
||||
inode->i_sb->s_bdev, iov, offset,
|
||||
nr_segs,
|
||||
@ -1259,7 +1266,8 @@ static int ocfs2_write_cluster(struct address_space *mapping,
|
||||
goto out;
|
||||
}
|
||||
} else if (unwritten) {
|
||||
ocfs2_init_dinode_extent_tree(&et, inode, wc->w_di_bh);
|
||||
ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(inode),
|
||||
wc->w_di_bh);
|
||||
ret = ocfs2_mark_extent_written(inode, &et,
|
||||
wc->w_handle, cpos, 1, phys,
|
||||
meta_ac, &wc->w_dealloc);
|
||||
@ -1448,6 +1456,9 @@ static int ocfs2_populate_write_desc(struct inode *inode,
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* We should already CoW the refcountd extent. */
|
||||
BUG_ON(ext_flags & OCFS2_EXT_REFCOUNTED);
|
||||
|
||||
/*
|
||||
* Assume worst case - that we're writing in
|
||||
* the middle of the extent.
|
||||
@ -1528,7 +1539,7 @@ static int ocfs2_write_begin_inline(struct address_space *mapping,
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = ocfs2_journal_access_di(handle, inode, wc->w_di_bh,
|
||||
ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), wc->w_di_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (ret) {
|
||||
ocfs2_commit_trans(osb, handle);
|
||||
@ -1699,6 +1710,19 @@ int ocfs2_write_begin_nolock(struct address_space *mapping,
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = ocfs2_check_range_for_refcount(inode, pos, len);
|
||||
if (ret < 0) {
|
||||
mlog_errno(ret);
|
||||
goto out;
|
||||
} else if (ret == 1) {
|
||||
ret = ocfs2_refcount_cow(inode, di_bh,
|
||||
wc->w_cpos, wc->w_clen, UINT_MAX);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ocfs2_populate_write_desc(inode, wc, &clusters_to_alloc,
|
||||
&extents_to_split);
|
||||
if (ret) {
|
||||
@ -1726,7 +1750,8 @@ int ocfs2_write_begin_nolock(struct address_space *mapping,
|
||||
(long long)i_size_read(inode), le32_to_cpu(di->i_clusters),
|
||||
clusters_to_alloc, extents_to_split);
|
||||
|
||||
ocfs2_init_dinode_extent_tree(&et, inode, wc->w_di_bh);
|
||||
ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(inode),
|
||||
wc->w_di_bh);
|
||||
ret = ocfs2_lock_allocators(inode, &et,
|
||||
clusters_to_alloc, extents_to_split,
|
||||
&data_ac, &meta_ac);
|
||||
@ -1773,7 +1798,7 @@ int ocfs2_write_begin_nolock(struct address_space *mapping,
|
||||
* We don't want this to fail in ocfs2_write_end(), so do it
|
||||
* here.
|
||||
*/
|
||||
ret = ocfs2_journal_access_di(handle, inode, wc->w_di_bh,
|
||||
ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), wc->w_di_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
|
@ -57,6 +57,8 @@ int ocfs2_read_inline_data(struct inode *inode, struct page *page,
|
||||
struct buffer_head *di_bh);
|
||||
int ocfs2_size_fits_inline_data(struct buffer_head *di_bh, u64 new_size);
|
||||
|
||||
int ocfs2_get_block(struct inode *inode, sector_t iblock,
|
||||
struct buffer_head *bh_result, int create);
|
||||
/* all ocfs2_dio_end_io()'s fault */
|
||||
#define ocfs2_iocb_is_rw_locked(iocb) \
|
||||
test_bit(0, (unsigned long *)&iocb->private)
|
||||
|
@ -52,12 +52,12 @@ enum ocfs2_state_bits {
|
||||
BUFFER_FNS(NeedsValidate, needs_validate);
|
||||
|
||||
int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh,
|
||||
struct inode *inode)
|
||||
struct ocfs2_caching_info *ci)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mlog_entry("(bh->b_blocknr = %llu, inode=%p)\n",
|
||||
(unsigned long long)bh->b_blocknr, inode);
|
||||
mlog_entry("(bh->b_blocknr = %llu, ci=%p)\n",
|
||||
(unsigned long long)bh->b_blocknr, ci);
|
||||
|
||||
BUG_ON(bh->b_blocknr < OCFS2_SUPER_BLOCK_BLKNO);
|
||||
BUG_ON(buffer_jbd(bh));
|
||||
@ -70,7 +70,7 @@ int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh,
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&OCFS2_I(inode)->ip_io_mutex);
|
||||
ocfs2_metadata_cache_io_lock(ci);
|
||||
|
||||
lock_buffer(bh);
|
||||
set_buffer_uptodate(bh);
|
||||
@ -85,7 +85,7 @@ int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh,
|
||||
wait_on_buffer(bh);
|
||||
|
||||
if (buffer_uptodate(bh)) {
|
||||
ocfs2_set_buffer_uptodate(inode, bh);
|
||||
ocfs2_set_buffer_uptodate(ci, bh);
|
||||
} else {
|
||||
/* We don't need to remove the clustered uptodate
|
||||
* information for this bh as it's not marked locally
|
||||
@ -94,7 +94,7 @@ int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh,
|
||||
put_bh(bh);
|
||||
}
|
||||
|
||||
mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
|
||||
ocfs2_metadata_cache_io_unlock(ci);
|
||||
out:
|
||||
mlog_exit(ret);
|
||||
return ret;
|
||||
@ -177,7 +177,7 @@ bail:
|
||||
return status;
|
||||
}
|
||||
|
||||
int ocfs2_read_blocks(struct inode *inode, u64 block, int nr,
|
||||
int ocfs2_read_blocks(struct ocfs2_caching_info *ci, u64 block, int nr,
|
||||
struct buffer_head *bhs[], int flags,
|
||||
int (*validate)(struct super_block *sb,
|
||||
struct buffer_head *bh))
|
||||
@ -185,11 +185,12 @@ int ocfs2_read_blocks(struct inode *inode, u64 block, int nr,
|
||||
int status = 0;
|
||||
int i, ignore_cache = 0;
|
||||
struct buffer_head *bh;
|
||||
struct super_block *sb = ocfs2_metadata_cache_get_super(ci);
|
||||
|
||||
mlog_entry("(inode=%p, block=(%llu), nr=(%d), flags=%d)\n",
|
||||
inode, (unsigned long long)block, nr, flags);
|
||||
mlog_entry("(ci=%p, block=(%llu), nr=(%d), flags=%d)\n",
|
||||
ci, (unsigned long long)block, nr, flags);
|
||||
|
||||
BUG_ON(!inode);
|
||||
BUG_ON(!ci);
|
||||
BUG_ON((flags & OCFS2_BH_READAHEAD) &&
|
||||
(flags & OCFS2_BH_IGNORE_CACHE));
|
||||
|
||||
@ -212,12 +213,12 @@ int ocfs2_read_blocks(struct inode *inode, u64 block, int nr,
|
||||
goto bail;
|
||||
}
|
||||
|
||||
mutex_lock(&OCFS2_I(inode)->ip_io_mutex);
|
||||
ocfs2_metadata_cache_io_lock(ci);
|
||||
for (i = 0 ; i < nr ; i++) {
|
||||
if (bhs[i] == NULL) {
|
||||
bhs[i] = sb_getblk(inode->i_sb, block++);
|
||||
bhs[i] = sb_getblk(sb, block++);
|
||||
if (bhs[i] == NULL) {
|
||||
mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
|
||||
ocfs2_metadata_cache_io_unlock(ci);
|
||||
status = -EIO;
|
||||
mlog_errno(status);
|
||||
goto bail;
|
||||
@ -250,11 +251,11 @@ int ocfs2_read_blocks(struct inode *inode, u64 block, int nr,
|
||||
* before our is-it-in-flight check.
|
||||
*/
|
||||
|
||||
if (!ignore_cache && !ocfs2_buffer_uptodate(inode, bh)) {
|
||||
if (!ignore_cache && !ocfs2_buffer_uptodate(ci, bh)) {
|
||||
mlog(ML_UPTODATE,
|
||||
"bh (%llu), inode %llu not uptodate\n",
|
||||
"bh (%llu), owner %llu not uptodate\n",
|
||||
(unsigned long long)bh->b_blocknr,
|
||||
(unsigned long long)OCFS2_I(inode)->ip_blkno);
|
||||
(unsigned long long)ocfs2_metadata_cache_owner(ci));
|
||||
/* We're using ignore_cache here to say
|
||||
* "go to disk" */
|
||||
ignore_cache = 1;
|
||||
@ -283,7 +284,7 @@ int ocfs2_read_blocks(struct inode *inode, u64 block, int nr,
|
||||
* previously submitted request than we are
|
||||
* done here. */
|
||||
if ((flags & OCFS2_BH_READAHEAD)
|
||||
&& ocfs2_buffer_read_ahead(inode, bh))
|
||||
&& ocfs2_buffer_read_ahead(ci, bh))
|
||||
continue;
|
||||
|
||||
lock_buffer(bh);
|
||||
@ -305,7 +306,7 @@ int ocfs2_read_blocks(struct inode *inode, u64 block, int nr,
|
||||
* buffer lock. */
|
||||
if (!(flags & OCFS2_BH_IGNORE_CACHE)
|
||||
&& !(flags & OCFS2_BH_READAHEAD)
|
||||
&& ocfs2_buffer_uptodate(inode, bh)) {
|
||||
&& ocfs2_buffer_uptodate(ci, bh)) {
|
||||
unlock_buffer(bh);
|
||||
continue;
|
||||
}
|
||||
@ -327,7 +328,7 @@ int ocfs2_read_blocks(struct inode *inode, u64 block, int nr,
|
||||
|
||||
if (!(flags & OCFS2_BH_READAHEAD)) {
|
||||
/* We know this can't have changed as we hold the
|
||||
* inode sem. Avoid doing any work on the bh if the
|
||||
* owner sem. Avoid doing any work on the bh if the
|
||||
* journal has it. */
|
||||
if (!buffer_jbd(bh))
|
||||
wait_on_buffer(bh);
|
||||
@ -351,7 +352,7 @@ int ocfs2_read_blocks(struct inode *inode, u64 block, int nr,
|
||||
* that better not have changed */
|
||||
BUG_ON(buffer_jbd(bh));
|
||||
clear_buffer_needs_validate(bh);
|
||||
status = validate(inode->i_sb, bh);
|
||||
status = validate(sb, bh);
|
||||
if (status) {
|
||||
put_bh(bh);
|
||||
bhs[i] = NULL;
|
||||
@ -363,9 +364,9 @@ int ocfs2_read_blocks(struct inode *inode, u64 block, int nr,
|
||||
/* Always set the buffer in the cache, even if it was
|
||||
* a forced read, or read-ahead which hasn't yet
|
||||
* completed. */
|
||||
ocfs2_set_buffer_uptodate(inode, bh);
|
||||
ocfs2_set_buffer_uptodate(ci, bh);
|
||||
}
|
||||
mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
|
||||
ocfs2_metadata_cache_io_unlock(ci);
|
||||
|
||||
mlog(ML_BH_IO, "block=(%llu), nr=(%d), cached=%s, flags=0x%x\n",
|
||||
(unsigned long long)block, nr,
|
||||
@ -399,7 +400,7 @@ static void ocfs2_check_super_or_backup(struct super_block *sb,
|
||||
|
||||
/*
|
||||
* Write super block and backups doesn't need to collaborate with journal,
|
||||
* so we don't need to lock ip_io_mutex and inode doesn't need to bea passed
|
||||
* so we don't need to lock ip_io_mutex and ci doesn't need to bea passed
|
||||
* into this function.
|
||||
*/
|
||||
int ocfs2_write_super_or_backup(struct ocfs2_super *osb,
|
||||
|
@ -33,7 +33,7 @@ void ocfs2_end_buffer_io_sync(struct buffer_head *bh,
|
||||
|
||||
int ocfs2_write_block(struct ocfs2_super *osb,
|
||||
struct buffer_head *bh,
|
||||
struct inode *inode);
|
||||
struct ocfs2_caching_info *ci);
|
||||
int ocfs2_read_blocks_sync(struct ocfs2_super *osb, u64 block,
|
||||
unsigned int nr, struct buffer_head *bhs[]);
|
||||
|
||||
@ -44,7 +44,7 @@ int ocfs2_read_blocks_sync(struct ocfs2_super *osb, u64 block,
|
||||
* be set even for a READAHEAD call, as it marks the buffer for later
|
||||
* validation.
|
||||
*/
|
||||
int ocfs2_read_blocks(struct inode *inode, u64 block, int nr,
|
||||
int ocfs2_read_blocks(struct ocfs2_caching_info *ci, u64 block, int nr,
|
||||
struct buffer_head *bhs[], int flags,
|
||||
int (*validate)(struct super_block *sb,
|
||||
struct buffer_head *bh));
|
||||
@ -55,7 +55,7 @@ int ocfs2_write_super_or_backup(struct ocfs2_super *osb,
|
||||
#define OCFS2_BH_IGNORE_CACHE 1
|
||||
#define OCFS2_BH_READAHEAD 8
|
||||
|
||||
static inline int ocfs2_read_block(struct inode *inode, u64 off,
|
||||
static inline int ocfs2_read_block(struct ocfs2_caching_info *ci, u64 off,
|
||||
struct buffer_head **bh,
|
||||
int (*validate)(struct super_block *sb,
|
||||
struct buffer_head *bh))
|
||||
@ -68,7 +68,7 @@ static inline int ocfs2_read_block(struct inode *inode, u64 off,
|
||||
goto bail;
|
||||
}
|
||||
|
||||
status = ocfs2_read_blocks(inode, off, 1, bh, 0, validate);
|
||||
status = ocfs2_read_blocks(ci, off, 1, bh, 0, validate);
|
||||
|
||||
bail:
|
||||
return status;
|
||||
|
@ -111,6 +111,7 @@ static struct mlog_attribute mlog_attrs[MLOG_MAX_BITS] = {
|
||||
define_mask(EXPORT),
|
||||
define_mask(XATTR),
|
||||
define_mask(QUOTA),
|
||||
define_mask(REFCOUNT),
|
||||
define_mask(ERROR),
|
||||
define_mask(NOTICE),
|
||||
define_mask(KTHREAD),
|
||||
|
@ -113,6 +113,7 @@
|
||||
#define ML_EXPORT 0x0000000010000000ULL /* ocfs2 export operations */
|
||||
#define ML_XATTR 0x0000000020000000ULL /* ocfs2 extended attributes */
|
||||
#define ML_QUOTA 0x0000000040000000ULL /* ocfs2 quota operations */
|
||||
#define ML_REFCOUNT 0x0000000080000000ULL /* refcount tree operations */
|
||||
/* bits that are infrequently given and frequently matched in the high word */
|
||||
#define ML_ERROR 0x0000000100000000ULL /* sent to KERN_ERR */
|
||||
#define ML_NOTICE 0x0000000200000000ULL /* setn to KERN_NOTICE */
|
||||
|
107
fs/ocfs2/dir.c
107
fs/ocfs2/dir.c
@ -176,7 +176,7 @@ static int ocfs2_dx_dir_link_trailer(struct inode *dir, handle_t *handle,
|
||||
struct ocfs2_dx_root_block *dx_root;
|
||||
struct ocfs2_dir_block_trailer *trailer;
|
||||
|
||||
ret = ocfs2_journal_access_dr(handle, dir, dx_root_bh,
|
||||
ret = ocfs2_journal_access_dr(handle, INODE_CACHE(dir), dx_root_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
@ -564,7 +564,8 @@ static int ocfs2_read_dir_block_direct(struct inode *dir, u64 phys,
|
||||
int ret;
|
||||
struct buffer_head *tmp = *bh;
|
||||
|
||||
ret = ocfs2_read_block(dir, phys, &tmp, ocfs2_validate_dir_block);
|
||||
ret = ocfs2_read_block(INODE_CACHE(dir), phys, &tmp,
|
||||
ocfs2_validate_dir_block);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
goto out;
|
||||
@ -622,7 +623,8 @@ static int ocfs2_read_dx_root(struct inode *dir, struct ocfs2_dinode *di,
|
||||
u64 blkno = le64_to_cpu(di->i_dx_root);
|
||||
struct buffer_head *tmp = *dx_root_bh;
|
||||
|
||||
ret = ocfs2_read_block(dir, blkno, &tmp, ocfs2_validate_dx_root);
|
||||
ret = ocfs2_read_block(INODE_CACHE(dir), blkno, &tmp,
|
||||
ocfs2_validate_dx_root);
|
||||
|
||||
/* If ocfs2_read_block() got us a new bh, pass it up. */
|
||||
if (!ret && !*dx_root_bh)
|
||||
@ -662,7 +664,8 @@ static int ocfs2_read_dx_leaf(struct inode *dir, u64 blkno,
|
||||
int ret;
|
||||
struct buffer_head *tmp = *dx_leaf_bh;
|
||||
|
||||
ret = ocfs2_read_block(dir, blkno, &tmp, ocfs2_validate_dx_leaf);
|
||||
ret = ocfs2_read_block(INODE_CACHE(dir), blkno, &tmp,
|
||||
ocfs2_validate_dx_leaf);
|
||||
|
||||
/* If ocfs2_read_block() got us a new bh, pass it up. */
|
||||
if (!ret && !*dx_leaf_bh)
|
||||
@ -680,7 +683,7 @@ static int ocfs2_read_dx_leaves(struct inode *dir, u64 start, int num,
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ocfs2_read_blocks(dir, start, num, dx_leaf_bhs, 0,
|
||||
ret = ocfs2_read_blocks(INODE_CACHE(dir), start, num, dx_leaf_bhs, 0,
|
||||
ocfs2_validate_dx_leaf);
|
||||
if (ret)
|
||||
mlog_errno(ret);
|
||||
@ -802,7 +805,8 @@ static int ocfs2_dx_dir_lookup_rec(struct inode *inode,
|
||||
struct ocfs2_extent_rec *rec = NULL;
|
||||
|
||||
if (el->l_tree_depth) {
|
||||
ret = ocfs2_find_leaf(inode, el, major_hash, &eb_bh);
|
||||
ret = ocfs2_find_leaf(INODE_CACHE(inode), el, major_hash,
|
||||
&eb_bh);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
goto out;
|
||||
@ -1133,7 +1137,8 @@ int ocfs2_update_entry(struct inode *dir, handle_t *handle,
|
||||
if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
|
||||
access = ocfs2_journal_access_di;
|
||||
|
||||
ret = access(handle, dir, de_bh, OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
ret = access(handle, INODE_CACHE(dir), de_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
goto out;
|
||||
@ -1176,7 +1181,7 @@ static int __ocfs2_delete_entry(handle_t *handle, struct inode *dir,
|
||||
goto bail;
|
||||
}
|
||||
if (de == de_del) {
|
||||
status = access(handle, dir, bh,
|
||||
status = access(handle, INODE_CACHE(dir), bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (status < 0) {
|
||||
status = -EIO;
|
||||
@ -1326,7 +1331,7 @@ static int ocfs2_delete_entry_dx(handle_t *handle, struct inode *dir,
|
||||
* the entry count needs to be updated. Also, we might be
|
||||
* adding to the start of the free list.
|
||||
*/
|
||||
ret = ocfs2_journal_access_dr(handle, dir, dx_root_bh,
|
||||
ret = ocfs2_journal_access_dr(handle, INODE_CACHE(dir), dx_root_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
@ -1334,7 +1339,7 @@ static int ocfs2_delete_entry_dx(handle_t *handle, struct inode *dir,
|
||||
}
|
||||
|
||||
if (!ocfs2_dx_root_inline(dx_root)) {
|
||||
ret = ocfs2_journal_access_dl(handle, dir,
|
||||
ret = ocfs2_journal_access_dl(handle, INODE_CACHE(dir),
|
||||
lookup->dl_dx_leaf_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (ret) {
|
||||
@ -1493,7 +1498,7 @@ static int __ocfs2_dx_dir_leaf_insert(struct inode *dir, handle_t *handle,
|
||||
int ret;
|
||||
struct ocfs2_dx_leaf *dx_leaf;
|
||||
|
||||
ret = ocfs2_journal_access_dl(handle, dir, dx_leaf_bh,
|
||||
ret = ocfs2_journal_access_dl(handle, INODE_CACHE(dir), dx_leaf_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
@ -1523,7 +1528,7 @@ static int ocfs2_dx_dir_insert(struct inode *dir, handle_t *handle,
|
||||
struct ocfs2_dx_root_block *dx_root;
|
||||
struct buffer_head *dx_root_bh = lookup->dl_dx_root_bh;
|
||||
|
||||
ret = ocfs2_journal_access_dr(handle, dir, dx_root_bh,
|
||||
ret = ocfs2_journal_access_dr(handle, INODE_CACHE(dir), dx_root_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
@ -1645,11 +1650,13 @@ int __ocfs2_add_entry(handle_t *handle,
|
||||
*/
|
||||
if (ocfs2_free_list_at_root(lookup)) {
|
||||
bh = lookup->dl_dx_root_bh;
|
||||
retval = ocfs2_journal_access_dr(handle, dir, bh,
|
||||
retval = ocfs2_journal_access_dr(handle,
|
||||
INODE_CACHE(dir), bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
} else {
|
||||
bh = lookup->dl_prev_leaf_bh;
|
||||
retval = ocfs2_journal_access_db(handle, dir, bh,
|
||||
retval = ocfs2_journal_access_db(handle,
|
||||
INODE_CACHE(dir), bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
}
|
||||
if (retval) {
|
||||
@ -1700,11 +1707,13 @@ int __ocfs2_add_entry(handle_t *handle,
|
||||
}
|
||||
|
||||
if (insert_bh == parent_fe_bh)
|
||||
status = ocfs2_journal_access_di(handle, dir,
|
||||
status = ocfs2_journal_access_di(handle,
|
||||
INODE_CACHE(dir),
|
||||
insert_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
else {
|
||||
status = ocfs2_journal_access_db(handle, dir,
|
||||
status = ocfs2_journal_access_db(handle,
|
||||
INODE_CACHE(dir),
|
||||
insert_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
|
||||
@ -2280,7 +2289,7 @@ static int ocfs2_fill_new_dir_id(struct ocfs2_super *osb,
|
||||
struct ocfs2_inline_data *data = &di->id2.i_data;
|
||||
unsigned int size = le16_to_cpu(data->id_count);
|
||||
|
||||
ret = ocfs2_journal_access_di(handle, inode, di_bh,
|
||||
ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
@ -2332,9 +2341,9 @@ static int ocfs2_fill_new_dir_el(struct ocfs2_super *osb,
|
||||
goto bail;
|
||||
}
|
||||
|
||||
ocfs2_set_new_buffer_uptodate(inode, new_bh);
|
||||
ocfs2_set_new_buffer_uptodate(INODE_CACHE(inode), new_bh);
|
||||
|
||||
status = ocfs2_journal_access_db(handle, inode, new_bh,
|
||||
status = ocfs2_journal_access_db(handle, INODE_CACHE(inode), new_bh,
|
||||
OCFS2_JOURNAL_ACCESS_CREATE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
@ -2418,9 +2427,9 @@ static int ocfs2_dx_dir_attach_index(struct ocfs2_super *osb,
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
ocfs2_set_new_buffer_uptodate(dir, dx_root_bh);
|
||||
ocfs2_set_new_buffer_uptodate(INODE_CACHE(dir), dx_root_bh);
|
||||
|
||||
ret = ocfs2_journal_access_dr(handle, dir, dx_root_bh,
|
||||
ret = ocfs2_journal_access_dr(handle, INODE_CACHE(dir), dx_root_bh,
|
||||
OCFS2_JOURNAL_ACCESS_CREATE);
|
||||
if (ret < 0) {
|
||||
mlog_errno(ret);
|
||||
@ -2454,7 +2463,7 @@ static int ocfs2_dx_dir_attach_index(struct ocfs2_super *osb,
|
||||
if (ret)
|
||||
mlog_errno(ret);
|
||||
|
||||
ret = ocfs2_journal_access_di(handle, dir, di_bh,
|
||||
ret = ocfs2_journal_access_di(handle, INODE_CACHE(dir), di_bh,
|
||||
OCFS2_JOURNAL_ACCESS_CREATE);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
@ -2495,9 +2504,9 @@ static int ocfs2_dx_dir_format_cluster(struct ocfs2_super *osb,
|
||||
}
|
||||
dx_leaves[i] = bh;
|
||||
|
||||
ocfs2_set_new_buffer_uptodate(dir, bh);
|
||||
ocfs2_set_new_buffer_uptodate(INODE_CACHE(dir), bh);
|
||||
|
||||
ret = ocfs2_journal_access_dl(handle, dir, bh,
|
||||
ret = ocfs2_journal_access_dl(handle, INODE_CACHE(dir), bh,
|
||||
OCFS2_JOURNAL_ACCESS_CREATE);
|
||||
if (ret < 0) {
|
||||
mlog_errno(ret);
|
||||
@ -2582,7 +2591,6 @@ static int ocfs2_dx_dir_new_cluster(struct inode *dir,
|
||||
{
|
||||
int ret;
|
||||
u64 phys_blkno;
|
||||
struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
|
||||
|
||||
ret = __ocfs2_dx_dir_new_cluster(dir, cpos, handle, data_ac, dx_leaves,
|
||||
num_dx_leaves, &phys_blkno);
|
||||
@ -2591,7 +2599,7 @@ static int ocfs2_dx_dir_new_cluster(struct inode *dir,
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = ocfs2_insert_extent(osb, handle, dir, et, cpos, phys_blkno, 1, 0,
|
||||
ret = ocfs2_insert_extent(handle, et, cpos, phys_blkno, 1, 0,
|
||||
meta_ac);
|
||||
if (ret)
|
||||
mlog_errno(ret);
|
||||
@ -2895,7 +2903,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
|
||||
struct ocfs2_extent_tree dx_et;
|
||||
int did_quota = 0, bytes_allocated = 0;
|
||||
|
||||
ocfs2_init_dinode_extent_tree(&et, dir, di_bh);
|
||||
ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(dir), di_bh);
|
||||
|
||||
alloc = ocfs2_clusters_for_bytes(sb, bytes);
|
||||
dx_alloc = 0;
|
||||
@ -3005,9 +3013,9 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
|
||||
goto out_commit;
|
||||
}
|
||||
|
||||
ocfs2_set_new_buffer_uptodate(dir, dirdata_bh);
|
||||
ocfs2_set_new_buffer_uptodate(INODE_CACHE(dir), dirdata_bh);
|
||||
|
||||
ret = ocfs2_journal_access_db(handle, dir, dirdata_bh,
|
||||
ret = ocfs2_journal_access_db(handle, INODE_CACHE(dir), dirdata_bh,
|
||||
OCFS2_JOURNAL_ACCESS_CREATE);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
@ -3060,7 +3068,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
|
||||
* We let the later dirent insert modify c/mtime - to the user
|
||||
* the data hasn't changed.
|
||||
*/
|
||||
ret = ocfs2_journal_access_di(handle, dir, di_bh,
|
||||
ret = ocfs2_journal_access_di(handle, INODE_CACHE(dir), di_bh,
|
||||
OCFS2_JOURNAL_ACCESS_CREATE);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
@ -3085,7 +3093,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
|
||||
* This should never fail as our extent list is empty and all
|
||||
* related blocks have been journaled already.
|
||||
*/
|
||||
ret = ocfs2_insert_extent(osb, handle, dir, &et, 0, blkno, len,
|
||||
ret = ocfs2_insert_extent(handle, &et, 0, blkno, len,
|
||||
0, NULL);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
@ -3117,8 +3125,10 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
|
||||
ocfs2_dx_dir_index_root_block(dir, dx_root_bh,
|
||||
dirdata_bh);
|
||||
} else {
|
||||
ocfs2_init_dx_root_extent_tree(&dx_et, dir, dx_root_bh);
|
||||
ret = ocfs2_insert_extent(osb, handle, dir, &dx_et, 0,
|
||||
ocfs2_init_dx_root_extent_tree(&dx_et,
|
||||
INODE_CACHE(dir),
|
||||
dx_root_bh);
|
||||
ret = ocfs2_insert_extent(handle, &dx_et, 0,
|
||||
dx_insert_blkno, 1, 0, NULL);
|
||||
if (ret)
|
||||
mlog_errno(ret);
|
||||
@ -3138,7 +3148,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
|
||||
}
|
||||
blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off);
|
||||
|
||||
ret = ocfs2_insert_extent(osb, handle, dir, &et, 1,
|
||||
ret = ocfs2_insert_extent(handle, &et, 1,
|
||||
blkno, len, 0, NULL);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
@ -3337,8 +3347,9 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,
|
||||
spin_lock(&OCFS2_I(dir)->ip_lock);
|
||||
if (dir_i_size == ocfs2_clusters_to_bytes(sb, OCFS2_I(dir)->ip_clusters)) {
|
||||
spin_unlock(&OCFS2_I(dir)->ip_lock);
|
||||
ocfs2_init_dinode_extent_tree(&et, dir, parent_fe_bh);
|
||||
num_free_extents = ocfs2_num_free_extents(osb, dir, &et);
|
||||
ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(dir),
|
||||
parent_fe_bh);
|
||||
num_free_extents = ocfs2_num_free_extents(osb, &et);
|
||||
if (num_free_extents < 0) {
|
||||
status = num_free_extents;
|
||||
mlog_errno(status);
|
||||
@ -3387,9 +3398,9 @@ do_extend:
|
||||
goto bail;
|
||||
}
|
||||
|
||||
ocfs2_set_new_buffer_uptodate(dir, new_bh);
|
||||
ocfs2_set_new_buffer_uptodate(INODE_CACHE(dir), new_bh);
|
||||
|
||||
status = ocfs2_journal_access_db(handle, dir, new_bh,
|
||||
status = ocfs2_journal_access_db(handle, INODE_CACHE(dir), new_bh,
|
||||
OCFS2_JOURNAL_ACCESS_CREATE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
@ -3829,7 +3840,7 @@ static int ocfs2_dx_dir_rebalance(struct ocfs2_super *osb, struct inode *dir,
|
||||
(unsigned long long)OCFS2_I(dir)->ip_blkno,
|
||||
(unsigned long long)leaf_blkno, insert_hash);
|
||||
|
||||
ocfs2_init_dx_root_extent_tree(&et, dir, dx_root_bh);
|
||||
ocfs2_init_dx_root_extent_tree(&et, INODE_CACHE(dir), dx_root_bh);
|
||||
|
||||
dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data;
|
||||
/*
|
||||
@ -3885,7 +3896,7 @@ static int ocfs2_dx_dir_rebalance(struct ocfs2_super *osb, struct inode *dir,
|
||||
}
|
||||
did_quota = 1;
|
||||
|
||||
ret = ocfs2_journal_access_dl(handle, dir, dx_leaf_bh,
|
||||
ret = ocfs2_journal_access_dl(handle, INODE_CACHE(dir), dx_leaf_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
@ -3949,7 +3960,8 @@ static int ocfs2_dx_dir_rebalance(struct ocfs2_super *osb, struct inode *dir,
|
||||
}
|
||||
|
||||
for (i = 0; i < num_dx_leaves; i++) {
|
||||
ret = ocfs2_journal_access_dl(handle, dir, orig_dx_leaves[i],
|
||||
ret = ocfs2_journal_access_dl(handle, INODE_CACHE(dir),
|
||||
orig_dx_leaves[i],
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
@ -4165,7 +4177,7 @@ static int ocfs2_expand_inline_dx_root(struct inode *dir,
|
||||
* failure to add the dx_root_bh to the journal won't result
|
||||
* us losing clusters.
|
||||
*/
|
||||
ret = ocfs2_journal_access_dr(handle, dir, dx_root_bh,
|
||||
ret = ocfs2_journal_access_dr(handle, INODE_CACHE(dir), dx_root_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
@ -4207,9 +4219,8 @@ static int ocfs2_expand_inline_dx_root(struct inode *dir,
|
||||
|
||||
/* This should never fail considering we start with an empty
|
||||
* dx_root. */
|
||||
ocfs2_init_dx_root_extent_tree(&et, dir, dx_root_bh);
|
||||
ret = ocfs2_insert_extent(osb, handle, dir, &et, 0,
|
||||
insert_blkno, 1, 0, NULL);
|
||||
ocfs2_init_dx_root_extent_tree(&et, INODE_CACHE(dir), dx_root_bh);
|
||||
ret = ocfs2_insert_extent(handle, &et, 0, insert_blkno, 1, 0, NULL);
|
||||
if (ret)
|
||||
mlog_errno(ret);
|
||||
did_quota = 0;
|
||||
@ -4469,7 +4480,7 @@ static int ocfs2_dx_dir_remove_index(struct inode *dir,
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
ret = ocfs2_journal_access_di(handle, dir, di_bh,
|
||||
ret = ocfs2_journal_access_di(handle, INODE_CACHE(dir), di_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
@ -4532,7 +4543,7 @@ int ocfs2_dx_dir_truncate(struct inode *dir, struct buffer_head *di_bh)
|
||||
if (ocfs2_dx_root_inline(dx_root))
|
||||
goto remove_index;
|
||||
|
||||
ocfs2_init_dx_root_extent_tree(&et, dir, dx_root_bh);
|
||||
ocfs2_init_dx_root_extent_tree(&et, INODE_CACHE(dir), dx_root_bh);
|
||||
|
||||
/* XXX: What if dr_clusters is too large? */
|
||||
while (le32_to_cpu(dx_root->dr_clusters)) {
|
||||
@ -4565,7 +4576,7 @@ remove_index:
|
||||
goto out;
|
||||
}
|
||||
|
||||
ocfs2_remove_from_cache(dir, dx_root_bh);
|
||||
ocfs2_remove_from_cache(INODE_CACHE(dir), dx_root_bh);
|
||||
out:
|
||||
ocfs2_schedule_truncate_log_flush(osb, 1);
|
||||
ocfs2_run_deallocs(osb, &dealloc);
|
||||
|
@ -212,14 +212,18 @@ static int dlm_purge_lockres(struct dlm_ctxt *dlm,
|
||||
spin_lock(&dlm->spinlock);
|
||||
}
|
||||
|
||||
spin_lock(&res->spinlock);
|
||||
if (!list_empty(&res->purge)) {
|
||||
mlog(0, "removing lockres %.*s:%p from purgelist, "
|
||||
"master = %d\n", res->lockname.len, res->lockname.name,
|
||||
res, master);
|
||||
list_del_init(&res->purge);
|
||||
spin_unlock(&res->spinlock);
|
||||
dlm_lockres_put(res);
|
||||
dlm->purge_count--;
|
||||
}
|
||||
} else
|
||||
spin_unlock(&res->spinlock);
|
||||
|
||||
__dlm_unhash_lockres(res);
|
||||
|
||||
/* lockres is not in the hash now. drop the flag and wake up
|
||||
|
@ -53,6 +53,7 @@
|
||||
#include "super.h"
|
||||
#include "uptodate.h"
|
||||
#include "quota.h"
|
||||
#include "refcounttree.h"
|
||||
|
||||
#include "buffer_head_io.h"
|
||||
|
||||
@ -110,6 +111,11 @@ static void ocfs2_dentry_post_unlock(struct ocfs2_super *osb,
|
||||
|
||||
static void ocfs2_set_qinfo_lvb(struct ocfs2_lock_res *lockres);
|
||||
|
||||
static int ocfs2_check_refcount_downconvert(struct ocfs2_lock_res *lockres,
|
||||
int new_level);
|
||||
static int ocfs2_refcount_convert_worker(struct ocfs2_lock_res *lockres,
|
||||
int blocking);
|
||||
|
||||
#define mlog_meta_lvb(__level, __lockres) ocfs2_dump_meta_lvb_info(__level, __PRETTY_FUNCTION__, __LINE__, __lockres)
|
||||
|
||||
/* This aids in debugging situations where a bad LVB might be involved. */
|
||||
@ -278,6 +284,12 @@ static struct ocfs2_lock_res_ops ocfs2_qinfo_lops = {
|
||||
.flags = LOCK_TYPE_REQUIRES_REFRESH | LOCK_TYPE_USES_LVB,
|
||||
};
|
||||
|
||||
static struct ocfs2_lock_res_ops ocfs2_refcount_block_lops = {
|
||||
.check_downconvert = ocfs2_check_refcount_downconvert,
|
||||
.downconvert_worker = ocfs2_refcount_convert_worker,
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
static inline int ocfs2_is_inode_lock(struct ocfs2_lock_res *lockres)
|
||||
{
|
||||
return lockres->l_type == OCFS2_LOCK_TYPE_META ||
|
||||
@ -306,6 +318,12 @@ static inline struct ocfs2_mem_dqinfo *ocfs2_lock_res_qinfo(struct ocfs2_lock_re
|
||||
return (struct ocfs2_mem_dqinfo *)lockres->l_priv;
|
||||
}
|
||||
|
||||
static inline struct ocfs2_refcount_tree *
|
||||
ocfs2_lock_res_refcount_tree(struct ocfs2_lock_res *res)
|
||||
{
|
||||
return container_of(res, struct ocfs2_refcount_tree, rf_lockres);
|
||||
}
|
||||
|
||||
static inline struct ocfs2_super *ocfs2_get_lockres_osb(struct ocfs2_lock_res *lockres)
|
||||
{
|
||||
if (lockres->l_ops->get_osb)
|
||||
@ -693,6 +711,17 @@ void ocfs2_qinfo_lock_res_init(struct ocfs2_lock_res *lockres,
|
||||
info);
|
||||
}
|
||||
|
||||
void ocfs2_refcount_lock_res_init(struct ocfs2_lock_res *lockres,
|
||||
struct ocfs2_super *osb, u64 ref_blkno,
|
||||
unsigned int generation)
|
||||
{
|
||||
ocfs2_lock_res_init_once(lockres);
|
||||
ocfs2_build_lock_name(OCFS2_LOCK_TYPE_REFCOUNT, ref_blkno,
|
||||
generation, lockres->l_name);
|
||||
ocfs2_lock_res_init_common(osb, lockres, OCFS2_LOCK_TYPE_REFCOUNT,
|
||||
&ocfs2_refcount_block_lops, osb);
|
||||
}
|
||||
|
||||
void ocfs2_lock_res_free(struct ocfs2_lock_res *res)
|
||||
{
|
||||
mlog_entry_void();
|
||||
@ -1548,8 +1577,10 @@ int ocfs2_rw_lock(struct inode *inode, int write)
|
||||
(unsigned long long)OCFS2_I(inode)->ip_blkno,
|
||||
write ? "EXMODE" : "PRMODE");
|
||||
|
||||
if (ocfs2_mount_local(osb))
|
||||
if (ocfs2_mount_local(osb)) {
|
||||
mlog_exit(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lockres = &OCFS2_I(inode)->ip_rw_lockres;
|
||||
|
||||
@ -2127,7 +2158,7 @@ static int ocfs2_inode_lock_update(struct inode *inode,
|
||||
|
||||
/* This will discard any caching information we might have had
|
||||
* for the inode metadata. */
|
||||
ocfs2_metadata_cache_purge(inode);
|
||||
ocfs2_metadata_cache_purge(INODE_CACHE(inode));
|
||||
|
||||
ocfs2_extent_map_trunc(inode, 0);
|
||||
|
||||
@ -3009,6 +3040,7 @@ static void ocfs2_unlock_ast(void *opaque, int error)
|
||||
"unlock_action %d\n", error, lockres->l_name,
|
||||
lockres->l_unlock_action);
|
||||
spin_unlock_irqrestore(&lockres->l_lock, flags);
|
||||
mlog_exit_void();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3495,11 +3527,11 @@ out:
|
||||
return UNBLOCK_CONTINUE;
|
||||
}
|
||||
|
||||
static int ocfs2_check_meta_downconvert(struct ocfs2_lock_res *lockres,
|
||||
int new_level)
|
||||
static int ocfs2_ci_checkpointed(struct ocfs2_caching_info *ci,
|
||||
struct ocfs2_lock_res *lockres,
|
||||
int new_level)
|
||||
{
|
||||
struct inode *inode = ocfs2_lock_res_inode(lockres);
|
||||
int checkpointed = ocfs2_inode_fully_checkpointed(inode);
|
||||
int checkpointed = ocfs2_ci_fully_checkpointed(ci);
|
||||
|
||||
BUG_ON(new_level != DLM_LOCK_NL && new_level != DLM_LOCK_PR);
|
||||
BUG_ON(lockres->l_level != DLM_LOCK_EX && !checkpointed);
|
||||
@ -3507,10 +3539,18 @@ static int ocfs2_check_meta_downconvert(struct ocfs2_lock_res *lockres,
|
||||
if (checkpointed)
|
||||
return 1;
|
||||
|
||||
ocfs2_start_checkpoint(OCFS2_SB(inode->i_sb));
|
||||
ocfs2_start_checkpoint(OCFS2_SB(ocfs2_metadata_cache_get_super(ci)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ocfs2_check_meta_downconvert(struct ocfs2_lock_res *lockres,
|
||||
int new_level)
|
||||
{
|
||||
struct inode *inode = ocfs2_lock_res_inode(lockres);
|
||||
|
||||
return ocfs2_ci_checkpointed(INODE_CACHE(inode), lockres, new_level);
|
||||
}
|
||||
|
||||
static void ocfs2_set_meta_lvb(struct ocfs2_lock_res *lockres)
|
||||
{
|
||||
struct inode *inode = ocfs2_lock_res_inode(lockres);
|
||||
@ -3640,6 +3680,26 @@ static int ocfs2_dentry_convert_worker(struct ocfs2_lock_res *lockres,
|
||||
return UNBLOCK_CONTINUE_POST;
|
||||
}
|
||||
|
||||
static int ocfs2_check_refcount_downconvert(struct ocfs2_lock_res *lockres,
|
||||
int new_level)
|
||||
{
|
||||
struct ocfs2_refcount_tree *tree =
|
||||
ocfs2_lock_res_refcount_tree(lockres);
|
||||
|
||||
return ocfs2_ci_checkpointed(&tree->rf_ci, lockres, new_level);
|
||||
}
|
||||
|
||||
static int ocfs2_refcount_convert_worker(struct ocfs2_lock_res *lockres,
|
||||
int blocking)
|
||||
{
|
||||
struct ocfs2_refcount_tree *tree =
|
||||
ocfs2_lock_res_refcount_tree(lockres);
|
||||
|
||||
ocfs2_metadata_cache_purge(&tree->rf_ci);
|
||||
|
||||
return UNBLOCK_CONTINUE;
|
||||
}
|
||||
|
||||
static void ocfs2_set_qinfo_lvb(struct ocfs2_lock_res *lockres)
|
||||
{
|
||||
struct ocfs2_qinfo_lvb *lvb;
|
||||
@ -3752,6 +3812,37 @@ bail:
|
||||
return status;
|
||||
}
|
||||
|
||||
int ocfs2_refcount_lock(struct ocfs2_refcount_tree *ref_tree, int ex)
|
||||
{
|
||||
int status;
|
||||
int level = ex ? DLM_LOCK_EX : DLM_LOCK_PR;
|
||||
struct ocfs2_lock_res *lockres = &ref_tree->rf_lockres;
|
||||
struct ocfs2_super *osb = lockres->l_priv;
|
||||
|
||||
|
||||
if (ocfs2_is_hard_readonly(osb))
|
||||
return -EROFS;
|
||||
|
||||
if (ocfs2_mount_local(osb))
|
||||
return 0;
|
||||
|
||||
status = ocfs2_cluster_lock(osb, lockres, level, 0, 0);
|
||||
if (status < 0)
|
||||
mlog_errno(status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void ocfs2_refcount_unlock(struct ocfs2_refcount_tree *ref_tree, int ex)
|
||||
{
|
||||
int level = ex ? DLM_LOCK_EX : DLM_LOCK_PR;
|
||||
struct ocfs2_lock_res *lockres = &ref_tree->rf_lockres;
|
||||
struct ocfs2_super *osb = lockres->l_priv;
|
||||
|
||||
if (!ocfs2_mount_local(osb))
|
||||
ocfs2_cluster_unlock(osb, lockres, level);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the filesystem locking protocol. It provides the lock handling
|
||||
* hooks for the underlying DLM. It has a maximum version number.
|
||||
|
@ -101,6 +101,9 @@ void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres,
|
||||
struct ocfs2_mem_dqinfo;
|
||||
void ocfs2_qinfo_lock_res_init(struct ocfs2_lock_res *lockres,
|
||||
struct ocfs2_mem_dqinfo *info);
|
||||
void ocfs2_refcount_lock_res_init(struct ocfs2_lock_res *lockres,
|
||||
struct ocfs2_super *osb, u64 ref_blkno,
|
||||
unsigned int generation);
|
||||
void ocfs2_lock_res_free(struct ocfs2_lock_res *res);
|
||||
int ocfs2_create_new_inode_locks(struct inode *inode);
|
||||
int ocfs2_drop_inode_locks(struct inode *inode);
|
||||
@ -148,6 +151,9 @@ int ocfs2_file_lock(struct file *file, int ex, int trylock);
|
||||
void ocfs2_file_unlock(struct file *file);
|
||||
int ocfs2_qinfo_lock(struct ocfs2_mem_dqinfo *oinfo, int ex);
|
||||
void ocfs2_qinfo_unlock(struct ocfs2_mem_dqinfo *oinfo, int ex);
|
||||
struct ocfs2_refcount_tree;
|
||||
int ocfs2_refcount_lock(struct ocfs2_refcount_tree *ref_tree, int ex);
|
||||
void ocfs2_refcount_unlock(struct ocfs2_refcount_tree *ref_tree, int ex);
|
||||
|
||||
|
||||
void ocfs2_mark_lockres_freeing(struct ocfs2_lock_res *lockres);
|
||||
|
@ -293,7 +293,7 @@ static int ocfs2_last_eb_is_empty(struct inode *inode,
|
||||
struct ocfs2_extent_block *eb;
|
||||
struct ocfs2_extent_list *el;
|
||||
|
||||
ret = ocfs2_read_extent_block(inode, last_eb_blk, &eb_bh);
|
||||
ret = ocfs2_read_extent_block(INODE_CACHE(inode), last_eb_blk, &eb_bh);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
goto out;
|
||||
@ -353,11 +353,11 @@ static int ocfs2_search_for_hole_index(struct ocfs2_extent_list *el,
|
||||
* eb_bh is NULL. Otherwise, eb_bh should point to the extent block
|
||||
* containing el.
|
||||
*/
|
||||
static int ocfs2_figure_hole_clusters(struct inode *inode,
|
||||
struct ocfs2_extent_list *el,
|
||||
struct buffer_head *eb_bh,
|
||||
u32 v_cluster,
|
||||
u32 *num_clusters)
|
||||
int ocfs2_figure_hole_clusters(struct ocfs2_caching_info *ci,
|
||||
struct ocfs2_extent_list *el,
|
||||
struct buffer_head *eb_bh,
|
||||
u32 v_cluster,
|
||||
u32 *num_clusters)
|
||||
{
|
||||
int ret, i;
|
||||
struct buffer_head *next_eb_bh = NULL;
|
||||
@ -375,7 +375,7 @@ static int ocfs2_figure_hole_clusters(struct inode *inode,
|
||||
if (le64_to_cpu(eb->h_next_leaf_blk) == 0ULL)
|
||||
goto no_more_extents;
|
||||
|
||||
ret = ocfs2_read_extent_block(inode,
|
||||
ret = ocfs2_read_extent_block(ci,
|
||||
le64_to_cpu(eb->h_next_leaf_blk),
|
||||
&next_eb_bh);
|
||||
if (ret) {
|
||||
@ -428,7 +428,8 @@ static int ocfs2_get_clusters_nocache(struct inode *inode,
|
||||
tree_height = le16_to_cpu(el->l_tree_depth);
|
||||
|
||||
if (tree_height > 0) {
|
||||
ret = ocfs2_find_leaf(inode, el, v_cluster, &eb_bh);
|
||||
ret = ocfs2_find_leaf(INODE_CACHE(inode), el, v_cluster,
|
||||
&eb_bh);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
goto out;
|
||||
@ -455,7 +456,8 @@ static int ocfs2_get_clusters_nocache(struct inode *inode,
|
||||
* field.
|
||||
*/
|
||||
if (hole_len) {
|
||||
ret = ocfs2_figure_hole_clusters(inode, el, eb_bh,
|
||||
ret = ocfs2_figure_hole_clusters(INODE_CACHE(inode),
|
||||
el, eb_bh,
|
||||
v_cluster, &len);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
@ -539,7 +541,8 @@ static void ocfs2_relative_extent_offsets(struct super_block *sb,
|
||||
|
||||
int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster,
|
||||
u32 *p_cluster, u32 *num_clusters,
|
||||
struct ocfs2_extent_list *el)
|
||||
struct ocfs2_extent_list *el,
|
||||
unsigned int *extent_flags)
|
||||
{
|
||||
int ret = 0, i;
|
||||
struct buffer_head *eb_bh = NULL;
|
||||
@ -548,7 +551,8 @@ int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster,
|
||||
u32 coff;
|
||||
|
||||
if (el->l_tree_depth) {
|
||||
ret = ocfs2_find_leaf(inode, el, v_cluster, &eb_bh);
|
||||
ret = ocfs2_find_leaf(INODE_CACHE(inode), el, v_cluster,
|
||||
&eb_bh);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
goto out;
|
||||
@ -590,6 +594,9 @@ int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster,
|
||||
*p_cluster = *p_cluster + coff;
|
||||
if (num_clusters)
|
||||
*num_clusters = ocfs2_rec_clusters(el, rec) - coff;
|
||||
|
||||
if (extent_flags)
|
||||
*extent_flags = rec->e_flags;
|
||||
}
|
||||
out:
|
||||
if (eb_bh)
|
||||
@ -862,8 +869,8 @@ int ocfs2_read_virt_blocks(struct inode *inode, u64 v_block, int nr,
|
||||
BUG_ON(bhs[done + i]->b_blocknr != (p_block + i));
|
||||
}
|
||||
|
||||
rc = ocfs2_read_blocks(inode, p_block, count, bhs + done,
|
||||
flags, validate);
|
||||
rc = ocfs2_read_blocks(INODE_CACHE(inode), p_block, count,
|
||||
bhs + done, flags, validate);
|
||||
if (rc) {
|
||||
mlog_errno(rc);
|
||||
break;
|
||||
|
@ -55,12 +55,18 @@ int ocfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
|
||||
int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster,
|
||||
u32 *p_cluster, u32 *num_clusters,
|
||||
struct ocfs2_extent_list *el);
|
||||
struct ocfs2_extent_list *el,
|
||||
unsigned int *extent_flags);
|
||||
|
||||
int ocfs2_read_virt_blocks(struct inode *inode, u64 v_block, int nr,
|
||||
struct buffer_head *bhs[], int flags,
|
||||
int (*validate)(struct super_block *sb,
|
||||
struct buffer_head *bh));
|
||||
int ocfs2_figure_hole_clusters(struct ocfs2_caching_info *ci,
|
||||
struct ocfs2_extent_list *el,
|
||||
struct buffer_head *eb_bh,
|
||||
u32 v_cluster,
|
||||
u32 *num_clusters);
|
||||
static inline int ocfs2_read_virt_block(struct inode *inode, u64 v_block,
|
||||
struct buffer_head **bh,
|
||||
int (*validate)(struct super_block *sb,
|
||||
|
151
fs/ocfs2/file.c
151
fs/ocfs2/file.c
@ -59,6 +59,7 @@
|
||||
#include "xattr.h"
|
||||
#include "acl.h"
|
||||
#include "quota.h"
|
||||
#include "refcounttree.h"
|
||||
|
||||
#include "buffer_head_io.h"
|
||||
|
||||
@ -259,7 +260,7 @@ int ocfs2_update_inode_atime(struct inode *inode,
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = ocfs2_journal_access_di(handle, inode, bh,
|
||||
ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
@ -334,6 +335,39 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ocfs2_cow_file_pos(struct inode *inode,
|
||||
struct buffer_head *fe_bh,
|
||||
u64 offset)
|
||||
{
|
||||
int status;
|
||||
u32 phys, cpos = offset >> OCFS2_SB(inode->i_sb)->s_clustersize_bits;
|
||||
unsigned int num_clusters = 0;
|
||||
unsigned int ext_flags = 0;
|
||||
|
||||
/*
|
||||
* If the new offset is aligned to the range of the cluster, there is
|
||||
* no space for ocfs2_zero_range_for_truncate to fill, so no need to
|
||||
* CoW either.
|
||||
*/
|
||||
if ((offset & (OCFS2_SB(inode->i_sb)->s_clustersize - 1)) == 0)
|
||||
return 0;
|
||||
|
||||
status = ocfs2_get_clusters(inode, cpos, &phys,
|
||||
&num_clusters, &ext_flags);
|
||||
if (status) {
|
||||
mlog_errno(status);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(ext_flags & OCFS2_EXT_REFCOUNTED))
|
||||
goto out;
|
||||
|
||||
return ocfs2_refcount_cow(inode, fe_bh, cpos, 1, cpos+1);
|
||||
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb,
|
||||
struct inode *inode,
|
||||
struct buffer_head *fe_bh,
|
||||
@ -346,6 +380,17 @@ static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb,
|
||||
|
||||
mlog_entry_void();
|
||||
|
||||
/*
|
||||
* We need to CoW the cluster contains the offset if it is reflinked
|
||||
* since we will call ocfs2_zero_range_for_truncate later which will
|
||||
* write "0" from offset to the end of the cluster.
|
||||
*/
|
||||
status = ocfs2_cow_file_pos(inode, fe_bh, new_i_size);
|
||||
if (status) {
|
||||
mlog_errno(status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* TODO: This needs to actually orphan the inode in this
|
||||
* transaction. */
|
||||
|
||||
@ -356,7 +401,7 @@ static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb,
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = ocfs2_journal_access_di(handle, inode, fe_bh,
|
||||
status = ocfs2_journal_access_di(handle, INODE_CACHE(inode), fe_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
@ -486,6 +531,8 @@ bail_unlock_sem:
|
||||
up_write(&OCFS2_I(inode)->ip_alloc_sem);
|
||||
|
||||
bail:
|
||||
if (!status && OCFS2_I(inode)->ip_clusters == 0)
|
||||
status = ocfs2_try_remove_refcount_tree(inode, di_bh);
|
||||
|
||||
mlog_exit(status);
|
||||
return status;
|
||||
@ -515,11 +562,10 @@ int ocfs2_add_inode_data(struct ocfs2_super *osb,
|
||||
int ret;
|
||||
struct ocfs2_extent_tree et;
|
||||
|
||||
ocfs2_init_dinode_extent_tree(&et, inode, fe_bh);
|
||||
ret = ocfs2_add_clusters_in_btree(osb, inode, logical_offset,
|
||||
clusters_to_add, mark_unwritten,
|
||||
&et, handle,
|
||||
data_ac, meta_ac, reason_ret);
|
||||
ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(inode), fe_bh);
|
||||
ret = ocfs2_add_clusters_in_btree(handle, &et, logical_offset,
|
||||
clusters_to_add, mark_unwritten,
|
||||
data_ac, meta_ac, reason_ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -564,7 +610,7 @@ restart_all:
|
||||
(unsigned long long)OCFS2_I(inode)->ip_blkno,
|
||||
(long long)i_size_read(inode), le32_to_cpu(fe->i_clusters),
|
||||
clusters_to_add);
|
||||
ocfs2_init_dinode_extent_tree(&et, inode, bh);
|
||||
ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(inode), bh);
|
||||
status = ocfs2_lock_allocators(inode, &et, clusters_to_add, 0,
|
||||
&data_ac, &meta_ac);
|
||||
if (status) {
|
||||
@ -593,7 +639,7 @@ restarted_transaction:
|
||||
/* reserve a write to the file entry early on - that we if we
|
||||
* run out of credits in the allocation path, we can still
|
||||
* update i_size. */
|
||||
status = ocfs2_journal_access_di(handle, inode, bh,
|
||||
status = ocfs2_journal_access_di(handle, INODE_CACHE(inode), bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
@ -1131,7 +1177,7 @@ static int __ocfs2_write_remove_suid(struct inode *inode,
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = ocfs2_journal_access_di(handle, inode, bh,
|
||||
ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (ret < 0) {
|
||||
mlog_errno(ret);
|
||||
@ -1395,7 +1441,7 @@ static int ocfs2_remove_inode_range(struct inode *inode,
|
||||
struct address_space *mapping = inode->i_mapping;
|
||||
struct ocfs2_extent_tree et;
|
||||
|
||||
ocfs2_init_dinode_extent_tree(&et, inode, di_bh);
|
||||
ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(inode), di_bh);
|
||||
ocfs2_init_dealloc_ctxt(&dealloc);
|
||||
|
||||
if (byte_len == 0)
|
||||
@ -1657,6 +1703,70 @@ static long ocfs2_fallocate(struct inode *inode, int mode, loff_t offset,
|
||||
OCFS2_IOC_RESVSP64, &sr, change_size);
|
||||
}
|
||||
|
||||
int ocfs2_check_range_for_refcount(struct inode *inode, loff_t pos,
|
||||
size_t count)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned int extent_flags;
|
||||
u32 cpos, clusters, extent_len, phys_cpos;
|
||||
struct super_block *sb = inode->i_sb;
|
||||
|
||||
if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb)) ||
|
||||
!(OCFS2_I(inode)->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL))
|
||||
return 0;
|
||||
|
||||
cpos = pos >> OCFS2_SB(sb)->s_clustersize_bits;
|
||||
clusters = ocfs2_clusters_for_bytes(sb, pos + count) - cpos;
|
||||
|
||||
while (clusters) {
|
||||
ret = ocfs2_get_clusters(inode, cpos, &phys_cpos, &extent_len,
|
||||
&extent_flags);
|
||||
if (ret < 0) {
|
||||
mlog_errno(ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (phys_cpos && (extent_flags & OCFS2_EXT_REFCOUNTED)) {
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (extent_len > clusters)
|
||||
extent_len = clusters;
|
||||
|
||||
clusters -= extent_len;
|
||||
cpos += extent_len;
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ocfs2_prepare_inode_for_refcount(struct inode *inode,
|
||||
loff_t pos, size_t count,
|
||||
int *meta_level)
|
||||
{
|
||||
int ret;
|
||||
struct buffer_head *di_bh = NULL;
|
||||
u32 cpos = pos >> OCFS2_SB(inode->i_sb)->s_clustersize_bits;
|
||||
u32 clusters =
|
||||
ocfs2_clusters_for_bytes(inode->i_sb, pos + count) - cpos;
|
||||
|
||||
ret = ocfs2_inode_lock(inode, &di_bh, 1);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
*meta_level = 1;
|
||||
|
||||
ret = ocfs2_refcount_cow(inode, di_bh, cpos, clusters, UINT_MAX);
|
||||
if (ret)
|
||||
mlog_errno(ret);
|
||||
out:
|
||||
brelse(di_bh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
|
||||
loff_t *ppos,
|
||||
size_t count,
|
||||
@ -1713,6 +1823,22 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
|
||||
|
||||
end = saved_pos + count;
|
||||
|
||||
ret = ocfs2_check_range_for_refcount(inode, saved_pos, count);
|
||||
if (ret == 1) {
|
||||
ocfs2_inode_unlock(inode, meta_level);
|
||||
meta_level = -1;
|
||||
|
||||
ret = ocfs2_prepare_inode_for_refcount(inode,
|
||||
saved_pos,
|
||||
count,
|
||||
&meta_level);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
mlog_errno(ret);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip the O_DIRECT checks if we don't need
|
||||
* them.
|
||||
@ -1759,7 +1885,8 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
|
||||
*ppos = saved_pos;
|
||||
|
||||
out_unlock:
|
||||
ocfs2_inode_unlock(inode, meta_level);
|
||||
if (meta_level >= 0)
|
||||
ocfs2_inode_unlock(inode, meta_level);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
|
@ -69,4 +69,6 @@ int ocfs2_update_inode_atime(struct inode *inode,
|
||||
int ocfs2_change_file_space(struct file *file, unsigned int cmd,
|
||||
struct ocfs2_space_resv *sr);
|
||||
|
||||
int ocfs2_check_range_for_refcount(struct inode *inode, loff_t pos,
|
||||
size_t count);
|
||||
#endif /* OCFS2_FILE_H */
|
||||
|
@ -53,6 +53,7 @@
|
||||
#include "sysfile.h"
|
||||
#include "uptodate.h"
|
||||
#include "xattr.h"
|
||||
#include "refcounttree.h"
|
||||
|
||||
#include "buffer_head_io.h"
|
||||
|
||||
@ -562,7 +563,8 @@ static int ocfs2_truncate_for_delete(struct ocfs2_super *osb,
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = ocfs2_journal_access_di(handle, inode, fe_bh,
|
||||
status = ocfs2_journal_access_di(handle, INODE_CACHE(inode),
|
||||
fe_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
@ -646,7 +648,7 @@ static int ocfs2_remove_inode(struct inode *inode,
|
||||
}
|
||||
|
||||
/* set the inodes dtime */
|
||||
status = ocfs2_journal_access_di(handle, inode, di_bh,
|
||||
status = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
@ -662,7 +664,7 @@ static int ocfs2_remove_inode(struct inode *inode,
|
||||
goto bail_commit;
|
||||
}
|
||||
|
||||
ocfs2_remove_from_cache(inode, di_bh);
|
||||
ocfs2_remove_from_cache(INODE_CACHE(inode), di_bh);
|
||||
vfs_dq_free_inode(inode);
|
||||
|
||||
status = ocfs2_free_dinode(handle, inode_alloc_inode,
|
||||
@ -781,6 +783,12 @@ static int ocfs2_wipe_inode(struct inode *inode,
|
||||
goto bail_unlock_dir;
|
||||
}
|
||||
|
||||
status = ocfs2_remove_refcount_tree(inode, di_bh);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
goto bail_unlock_dir;
|
||||
}
|
||||
|
||||
status = ocfs2_remove_inode(inode, di_bh, orphan_dir_inode,
|
||||
orphan_dir_bh);
|
||||
if (status < 0)
|
||||
@ -1112,13 +1120,14 @@ void ocfs2_clear_inode(struct inode *inode)
|
||||
ocfs2_lock_res_free(&oi->ip_inode_lockres);
|
||||
ocfs2_lock_res_free(&oi->ip_open_lockres);
|
||||
|
||||
ocfs2_metadata_cache_purge(inode);
|
||||
ocfs2_metadata_cache_exit(INODE_CACHE(inode));
|
||||
|
||||
mlog_bug_on_msg(oi->ip_metadata_cache.ci_num_cached,
|
||||
mlog_bug_on_msg(INODE_CACHE(inode)->ci_num_cached,
|
||||
"Clear inode of %llu, inode has %u cache items\n",
|
||||
(unsigned long long)oi->ip_blkno, oi->ip_metadata_cache.ci_num_cached);
|
||||
(unsigned long long)oi->ip_blkno,
|
||||
INODE_CACHE(inode)->ci_num_cached);
|
||||
|
||||
mlog_bug_on_msg(!(oi->ip_flags & OCFS2_INODE_CACHE_INLINE),
|
||||
mlog_bug_on_msg(!(INODE_CACHE(inode)->ci_flags & OCFS2_CACHE_FL_INLINE),
|
||||
"Clear inode of %llu, inode has a bad flag\n",
|
||||
(unsigned long long)oi->ip_blkno);
|
||||
|
||||
@ -1145,9 +1154,7 @@ void ocfs2_clear_inode(struct inode *inode)
|
||||
(unsigned long long)oi->ip_blkno, oi->ip_open_count);
|
||||
|
||||
/* Clear all other flags. */
|
||||
oi->ip_flags = OCFS2_INODE_CACHE_INLINE;
|
||||
oi->ip_created_trans = 0;
|
||||
oi->ip_last_trans = 0;
|
||||
oi->ip_flags = 0;
|
||||
oi->ip_dir_start_lookup = 0;
|
||||
oi->ip_blkno = 0ULL;
|
||||
|
||||
@ -1239,7 +1246,7 @@ int ocfs2_mark_inode_dirty(handle_t *handle,
|
||||
mlog_entry("(inode %llu)\n",
|
||||
(unsigned long long)OCFS2_I(inode)->ip_blkno);
|
||||
|
||||
status = ocfs2_journal_access_di(handle, inode, bh,
|
||||
status = ocfs2_journal_access_di(handle, INODE_CACHE(inode), bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
@ -1380,8 +1387,8 @@ int ocfs2_read_inode_block_full(struct inode *inode, struct buffer_head **bh,
|
||||
int rc;
|
||||
struct buffer_head *tmp = *bh;
|
||||
|
||||
rc = ocfs2_read_blocks(inode, OCFS2_I(inode)->ip_blkno, 1, &tmp,
|
||||
flags, ocfs2_validate_inode_block);
|
||||
rc = ocfs2_read_blocks(INODE_CACHE(inode), OCFS2_I(inode)->ip_blkno,
|
||||
1, &tmp, flags, ocfs2_validate_inode_block);
|
||||
|
||||
/* If ocfs2_read_blocks() got us a new bh, pass it up. */
|
||||
if (!rc && !*bh)
|
||||
@ -1394,3 +1401,56 @@ int ocfs2_read_inode_block(struct inode *inode, struct buffer_head **bh)
|
||||
{
|
||||
return ocfs2_read_inode_block_full(inode, bh, 0);
|
||||
}
|
||||
|
||||
|
||||
static u64 ocfs2_inode_cache_owner(struct ocfs2_caching_info *ci)
|
||||
{
|
||||
struct ocfs2_inode_info *oi = cache_info_to_inode(ci);
|
||||
|
||||
return oi->ip_blkno;
|
||||
}
|
||||
|
||||
static struct super_block *ocfs2_inode_cache_get_super(struct ocfs2_caching_info *ci)
|
||||
{
|
||||
struct ocfs2_inode_info *oi = cache_info_to_inode(ci);
|
||||
|
||||
return oi->vfs_inode.i_sb;
|
||||
}
|
||||
|
||||
static void ocfs2_inode_cache_lock(struct ocfs2_caching_info *ci)
|
||||
{
|
||||
struct ocfs2_inode_info *oi = cache_info_to_inode(ci);
|
||||
|
||||
spin_lock(&oi->ip_lock);
|
||||
}
|
||||
|
||||
static void ocfs2_inode_cache_unlock(struct ocfs2_caching_info *ci)
|
||||
{
|
||||
struct ocfs2_inode_info *oi = cache_info_to_inode(ci);
|
||||
|
||||
spin_unlock(&oi->ip_lock);
|
||||
}
|
||||
|
||||
static void ocfs2_inode_cache_io_lock(struct ocfs2_caching_info *ci)
|
||||
{
|
||||
struct ocfs2_inode_info *oi = cache_info_to_inode(ci);
|
||||
|
||||
mutex_lock(&oi->ip_io_mutex);
|
||||
}
|
||||
|
||||
static void ocfs2_inode_cache_io_unlock(struct ocfs2_caching_info *ci)
|
||||
{
|
||||
struct ocfs2_inode_info *oi = cache_info_to_inode(ci);
|
||||
|
||||
mutex_unlock(&oi->ip_io_mutex);
|
||||
}
|
||||
|
||||
const struct ocfs2_caching_operations ocfs2_inode_caching_ops = {
|
||||
.co_owner = ocfs2_inode_cache_owner,
|
||||
.co_get_super = ocfs2_inode_cache_get_super,
|
||||
.co_cache_lock = ocfs2_inode_cache_lock,
|
||||
.co_cache_unlock = ocfs2_inode_cache_unlock,
|
||||
.co_io_lock = ocfs2_inode_cache_io_lock,
|
||||
.co_io_unlock = ocfs2_inode_cache_io_unlock,
|
||||
};
|
||||
|
||||
|
@ -60,12 +60,6 @@ struct ocfs2_inode_info
|
||||
|
||||
u32 ip_dir_start_lookup;
|
||||
|
||||
/* next two are protected by trans_inc_lock */
|
||||
/* which transaction were we created on? Zero if none. */
|
||||
unsigned long ip_created_trans;
|
||||
/* last transaction we were a part of. */
|
||||
unsigned long ip_last_trans;
|
||||
|
||||
struct ocfs2_caching_info ip_metadata_cache;
|
||||
|
||||
struct ocfs2_extent_map ip_extent_map;
|
||||
@ -106,8 +100,6 @@ struct ocfs2_inode_info
|
||||
#define OCFS2_INODE_MAYBE_ORPHANED 0x00000020
|
||||
/* Does someone have the file open O_DIRECT */
|
||||
#define OCFS2_INODE_OPEN_DIRECT 0x00000040
|
||||
/* Indicates that the metadata cache should be used as an array. */
|
||||
#define OCFS2_INODE_CACHE_INLINE 0x00000080
|
||||
|
||||
static inline struct ocfs2_inode_info *OCFS2_I(struct inode *inode)
|
||||
{
|
||||
@ -120,6 +112,12 @@ static inline struct ocfs2_inode_info *OCFS2_I(struct inode *inode)
|
||||
extern struct kmem_cache *ocfs2_inode_cache;
|
||||
|
||||
extern const struct address_space_operations ocfs2_aops;
|
||||
extern const struct ocfs2_caching_operations ocfs2_inode_caching_ops;
|
||||
|
||||
static inline struct ocfs2_caching_info *INODE_CACHE(struct inode *inode)
|
||||
{
|
||||
return &OCFS2_I(inode)->ip_metadata_cache;
|
||||
}
|
||||
|
||||
void ocfs2_clear_inode(struct inode *inode);
|
||||
void ocfs2_delete_inode(struct inode *inode);
|
||||
@ -172,4 +170,10 @@ int ocfs2_read_inode_block(struct inode *inode, struct buffer_head **bh);
|
||||
/* The same, but can be passed OCFS2_BH_* flags */
|
||||
int ocfs2_read_inode_block_full(struct inode *inode, struct buffer_head **bh,
|
||||
int flags);
|
||||
|
||||
static inline struct ocfs2_inode_info *cache_info_to_inode(struct ocfs2_caching_info *ci)
|
||||
{
|
||||
return container_of(ci, struct ocfs2_inode_info, ip_metadata_cache);
|
||||
}
|
||||
|
||||
#endif /* OCFS2_INODE_H */
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "ocfs2_fs.h"
|
||||
#include "ioctl.h"
|
||||
#include "resize.h"
|
||||
#include "refcounttree.h"
|
||||
|
||||
#include <linux/ext2_fs.h>
|
||||
|
||||
@ -115,6 +116,9 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
int status;
|
||||
struct ocfs2_space_resv sr;
|
||||
struct ocfs2_new_group_input input;
|
||||
struct reflink_arguments args;
|
||||
const char *old_path, *new_path;
|
||||
bool preserve;
|
||||
|
||||
switch (cmd) {
|
||||
case OCFS2_IOC_GETFLAGS:
|
||||
@ -160,6 +164,15 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
return -EFAULT;
|
||||
|
||||
return ocfs2_group_add(inode, &input);
|
||||
case OCFS2_IOC_REFLINK:
|
||||
if (copy_from_user(&args, (struct reflink_arguments *)arg,
|
||||
sizeof(args)))
|
||||
return -EFAULT;
|
||||
old_path = (const char *)(unsigned long)args.old_path;
|
||||
new_path = (const char *)(unsigned long)args.new_path;
|
||||
preserve = (args.preserve != 0);
|
||||
|
||||
return ocfs2_reflink_ioctl(inode, old_path, new_path, preserve);
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
@ -182,6 +195,7 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)
|
||||
case OCFS2_IOC_GROUP_EXTEND:
|
||||
case OCFS2_IOC_GROUP_ADD:
|
||||
case OCFS2_IOC_GROUP_ADD64:
|
||||
case OCFS2_IOC_REFLINK:
|
||||
break;
|
||||
default:
|
||||
return -ENOIOCTLCMD;
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "slot_map.h"
|
||||
#include "super.h"
|
||||
#include "sysfile.h"
|
||||
#include "uptodate.h"
|
||||
#include "quota.h"
|
||||
|
||||
#include "buffer_head_io.h"
|
||||
@ -554,6 +555,14 @@ static struct ocfs2_triggers eb_triggers = {
|
||||
.ot_offset = offsetof(struct ocfs2_extent_block, h_check),
|
||||
};
|
||||
|
||||
static struct ocfs2_triggers rb_triggers = {
|
||||
.ot_triggers = {
|
||||
.t_commit = ocfs2_commit_trigger,
|
||||
.t_abort = ocfs2_abort_trigger,
|
||||
},
|
||||
.ot_offset = offsetof(struct ocfs2_refcount_block, rf_check),
|
||||
};
|
||||
|
||||
static struct ocfs2_triggers gd_triggers = {
|
||||
.ot_triggers = {
|
||||
.t_commit = ocfs2_commit_trigger,
|
||||
@ -601,14 +610,16 @@ static struct ocfs2_triggers dl_triggers = {
|
||||
};
|
||||
|
||||
static int __ocfs2_journal_access(handle_t *handle,
|
||||
struct inode *inode,
|
||||
struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh,
|
||||
struct ocfs2_triggers *triggers,
|
||||
int type)
|
||||
{
|
||||
int status;
|
||||
struct ocfs2_super *osb =
|
||||
OCFS2_SB(ocfs2_metadata_cache_get_super(ci));
|
||||
|
||||
BUG_ON(!inode);
|
||||
BUG_ON(!ci || !ci->ci_ops);
|
||||
BUG_ON(!handle);
|
||||
BUG_ON(!bh);
|
||||
|
||||
@ -627,15 +638,15 @@ static int __ocfs2_journal_access(handle_t *handle,
|
||||
BUG();
|
||||
}
|
||||
|
||||
/* Set the current transaction information on the inode so
|
||||
/* Set the current transaction information on the ci so
|
||||
* that the locking code knows whether it can drop it's locks
|
||||
* on this inode or not. We're protected from the commit
|
||||
* on this ci or not. We're protected from the commit
|
||||
* thread updating the current transaction id until
|
||||
* ocfs2_commit_trans() because ocfs2_start_trans() took
|
||||
* j_trans_barrier for us. */
|
||||
ocfs2_set_inode_lock_trans(OCFS2_SB(inode->i_sb)->journal, inode);
|
||||
ocfs2_set_ci_lock_trans(osb->journal, ci);
|
||||
|
||||
mutex_lock(&OCFS2_I(inode)->ip_io_mutex);
|
||||
ocfs2_metadata_cache_io_lock(ci);
|
||||
switch (type) {
|
||||
case OCFS2_JOURNAL_ACCESS_CREATE:
|
||||
case OCFS2_JOURNAL_ACCESS_WRITE:
|
||||
@ -650,9 +661,9 @@ static int __ocfs2_journal_access(handle_t *handle,
|
||||
status = -EINVAL;
|
||||
mlog(ML_ERROR, "Uknown access type!\n");
|
||||
}
|
||||
if (!status && ocfs2_meta_ecc(OCFS2_SB(inode->i_sb)) && triggers)
|
||||
if (!status && ocfs2_meta_ecc(osb) && triggers)
|
||||
jbd2_journal_set_triggers(bh, &triggers->ot_triggers);
|
||||
mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
|
||||
ocfs2_metadata_cache_io_unlock(ci);
|
||||
|
||||
if (status < 0)
|
||||
mlog(ML_ERROR, "Error %d getting %d access to buffer!\n",
|
||||
@ -662,66 +673,65 @@ static int __ocfs2_journal_access(handle_t *handle,
|
||||
return status;
|
||||
}
|
||||
|
||||
int ocfs2_journal_access_di(handle_t *handle, struct inode *inode,
|
||||
struct buffer_head *bh, int type)
|
||||
{
|
||||
return __ocfs2_journal_access(handle, inode, bh, &di_triggers,
|
||||
type);
|
||||
}
|
||||
|
||||
int ocfs2_journal_access_eb(handle_t *handle, struct inode *inode,
|
||||
int ocfs2_journal_access_di(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh, int type)
|
||||
{
|
||||
return __ocfs2_journal_access(handle, inode, bh, &eb_triggers,
|
||||
type);
|
||||
return __ocfs2_journal_access(handle, ci, bh, &di_triggers, type);
|
||||
}
|
||||
|
||||
int ocfs2_journal_access_gd(handle_t *handle, struct inode *inode,
|
||||
int ocfs2_journal_access_eb(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh, int type)
|
||||
{
|
||||
return __ocfs2_journal_access(handle, inode, bh, &gd_triggers,
|
||||
type);
|
||||
return __ocfs2_journal_access(handle, ci, bh, &eb_triggers, type);
|
||||
}
|
||||
|
||||
int ocfs2_journal_access_db(handle_t *handle, struct inode *inode,
|
||||
int ocfs2_journal_access_rb(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh, int type)
|
||||
{
|
||||
return __ocfs2_journal_access(handle, inode, bh, &db_triggers,
|
||||
return __ocfs2_journal_access(handle, ci, bh, &rb_triggers,
|
||||
type);
|
||||
}
|
||||
|
||||
int ocfs2_journal_access_xb(handle_t *handle, struct inode *inode,
|
||||
int ocfs2_journal_access_gd(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh, int type)
|
||||
{
|
||||
return __ocfs2_journal_access(handle, inode, bh, &xb_triggers,
|
||||
type);
|
||||
return __ocfs2_journal_access(handle, ci, bh, &gd_triggers, type);
|
||||
}
|
||||
|
||||
int ocfs2_journal_access_dq(handle_t *handle, struct inode *inode,
|
||||
int ocfs2_journal_access_db(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh, int type)
|
||||
{
|
||||
return __ocfs2_journal_access(handle, inode, bh, &dq_triggers,
|
||||
type);
|
||||
return __ocfs2_journal_access(handle, ci, bh, &db_triggers, type);
|
||||
}
|
||||
|
||||
int ocfs2_journal_access_dr(handle_t *handle, struct inode *inode,
|
||||
int ocfs2_journal_access_xb(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh, int type)
|
||||
{
|
||||
return __ocfs2_journal_access(handle, inode, bh, &dr_triggers,
|
||||
type);
|
||||
return __ocfs2_journal_access(handle, ci, bh, &xb_triggers, type);
|
||||
}
|
||||
|
||||
int ocfs2_journal_access_dl(handle_t *handle, struct inode *inode,
|
||||
int ocfs2_journal_access_dq(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh, int type)
|
||||
{
|
||||
return __ocfs2_journal_access(handle, inode, bh, &dl_triggers,
|
||||
type);
|
||||
return __ocfs2_journal_access(handle, ci, bh, &dq_triggers, type);
|
||||
}
|
||||
|
||||
int ocfs2_journal_access(handle_t *handle, struct inode *inode,
|
||||
int ocfs2_journal_access_dr(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh, int type)
|
||||
{
|
||||
return __ocfs2_journal_access(handle, ci, bh, &dr_triggers, type);
|
||||
}
|
||||
|
||||
int ocfs2_journal_access_dl(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh, int type)
|
||||
{
|
||||
return __ocfs2_journal_access(handle, ci, bh, &dl_triggers, type);
|
||||
}
|
||||
|
||||
int ocfs2_journal_access(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh, int type)
|
||||
{
|
||||
return __ocfs2_journal_access(handle, inode, bh, NULL, type);
|
||||
return __ocfs2_journal_access(handle, ci, bh, NULL, type);
|
||||
}
|
||||
|
||||
int ocfs2_journal_dirty(handle_t *handle,
|
||||
@ -898,7 +908,7 @@ static int ocfs2_journal_toggle_dirty(struct ocfs2_super *osb,
|
||||
ocfs2_bump_recovery_generation(fe);
|
||||
|
||||
ocfs2_compute_meta_ecc(osb->sb, bh->b_data, &fe->i_check);
|
||||
status = ocfs2_write_block(osb, bh, journal->j_inode);
|
||||
status = ocfs2_write_block(osb, bh, INODE_CACHE(journal->j_inode));
|
||||
if (status < 0)
|
||||
mlog_errno(status);
|
||||
|
||||
@ -1642,7 +1652,7 @@ static int ocfs2_replay_journal(struct ocfs2_super *osb,
|
||||
ocfs2_get_recovery_generation(fe);
|
||||
|
||||
ocfs2_compute_meta_ecc(osb->sb, bh->b_data, &fe->i_check);
|
||||
status = ocfs2_write_block(osb, bh, inode);
|
||||
status = ocfs2_write_block(osb, bh, INODE_CACHE(inode));
|
||||
if (status < 0)
|
||||
mlog_errno(status);
|
||||
|
||||
|
@ -90,56 +90,66 @@ static inline unsigned long ocfs2_inc_trans_id(struct ocfs2_journal *j)
|
||||
return old_id;
|
||||
}
|
||||
|
||||
static inline void ocfs2_set_inode_lock_trans(struct ocfs2_journal *journal,
|
||||
struct inode *inode)
|
||||
static inline void ocfs2_set_ci_lock_trans(struct ocfs2_journal *journal,
|
||||
struct ocfs2_caching_info *ci)
|
||||
{
|
||||
spin_lock(&trans_inc_lock);
|
||||
OCFS2_I(inode)->ip_last_trans = journal->j_trans_id;
|
||||
ci->ci_last_trans = journal->j_trans_id;
|
||||
spin_unlock(&trans_inc_lock);
|
||||
}
|
||||
|
||||
/* Used to figure out whether it's safe to drop a metadata lock on an
|
||||
* inode. Returns true if all the inodes changes have been
|
||||
* cached object. Returns true if all the object's changes have been
|
||||
* checkpointed to disk. You should be holding the spinlock on the
|
||||
* metadata lock while calling this to be sure that nobody can take
|
||||
* the lock and put it on another transaction. */
|
||||
static inline int ocfs2_inode_fully_checkpointed(struct inode *inode)
|
||||
static inline int ocfs2_ci_fully_checkpointed(struct ocfs2_caching_info *ci)
|
||||
{
|
||||
int ret;
|
||||
struct ocfs2_journal *journal = OCFS2_SB(inode->i_sb)->journal;
|
||||
struct ocfs2_journal *journal =
|
||||
OCFS2_SB(ocfs2_metadata_cache_get_super(ci))->journal;
|
||||
|
||||
spin_lock(&trans_inc_lock);
|
||||
ret = time_after(journal->j_trans_id, OCFS2_I(inode)->ip_last_trans);
|
||||
ret = time_after(journal->j_trans_id, ci->ci_last_trans);
|
||||
spin_unlock(&trans_inc_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* convenience function to check if an inode is still new (has never
|
||||
* hit disk) Will do you a favor and set created_trans = 0 when you've
|
||||
* been checkpointed. returns '1' if the inode is still new. */
|
||||
static inline int ocfs2_inode_is_new(struct inode *inode)
|
||||
/* convenience function to check if an object backed by struct
|
||||
* ocfs2_caching_info is still new (has never hit disk) Will do you a
|
||||
* favor and set created_trans = 0 when you've
|
||||
* been checkpointed. returns '1' if the ci is still new. */
|
||||
static inline int ocfs2_ci_is_new(struct ocfs2_caching_info *ci)
|
||||
{
|
||||
int ret;
|
||||
struct ocfs2_journal *journal =
|
||||
OCFS2_SB(ocfs2_metadata_cache_get_super(ci))->journal;
|
||||
|
||||
spin_lock(&trans_inc_lock);
|
||||
ret = !(time_after(journal->j_trans_id, ci->ci_created_trans));
|
||||
if (!ret)
|
||||
ci->ci_created_trans = 0;
|
||||
spin_unlock(&trans_inc_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Wrapper for inodes so we can check system files */
|
||||
static inline int ocfs2_inode_is_new(struct inode *inode)
|
||||
{
|
||||
/* System files are never "new" as they're written out by
|
||||
* mkfs. This helps us early during mount, before we have the
|
||||
* journal open and j_trans_id could be junk. */
|
||||
if (OCFS2_I(inode)->ip_flags & OCFS2_INODE_SYSTEM_FILE)
|
||||
return 0;
|
||||
spin_lock(&trans_inc_lock);
|
||||
ret = !(time_after(OCFS2_SB(inode->i_sb)->journal->j_trans_id,
|
||||
OCFS2_I(inode)->ip_created_trans));
|
||||
if (!ret)
|
||||
OCFS2_I(inode)->ip_created_trans = 0;
|
||||
spin_unlock(&trans_inc_lock);
|
||||
return ret;
|
||||
|
||||
return ocfs2_ci_is_new(INODE_CACHE(inode));
|
||||
}
|
||||
|
||||
static inline void ocfs2_inode_set_new(struct ocfs2_super *osb,
|
||||
struct inode *inode)
|
||||
static inline void ocfs2_ci_set_new(struct ocfs2_super *osb,
|
||||
struct ocfs2_caching_info *ci)
|
||||
{
|
||||
spin_lock(&trans_inc_lock);
|
||||
OCFS2_I(inode)->ip_created_trans = osb->journal->j_trans_id;
|
||||
ci->ci_created_trans = osb->journal->j_trans_id;
|
||||
spin_unlock(&trans_inc_lock);
|
||||
}
|
||||
|
||||
@ -200,7 +210,7 @@ static inline void ocfs2_checkpoint_inode(struct inode *inode)
|
||||
if (ocfs2_mount_local(osb))
|
||||
return;
|
||||
|
||||
if (!ocfs2_inode_fully_checkpointed(inode)) {
|
||||
if (!ocfs2_ci_fully_checkpointed(INODE_CACHE(inode))) {
|
||||
/* WARNING: This only kicks off a single
|
||||
* checkpoint. If someone races you and adds more
|
||||
* metadata to the journal, you won't know, and will
|
||||
@ -210,7 +220,7 @@ static inline void ocfs2_checkpoint_inode(struct inode *inode)
|
||||
ocfs2_start_checkpoint(osb);
|
||||
|
||||
wait_event(osb->journal->j_checkpointed,
|
||||
ocfs2_inode_fully_checkpointed(inode));
|
||||
ocfs2_ci_fully_checkpointed(INODE_CACHE(inode)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -266,31 +276,34 @@ int ocfs2_extend_trans(handle_t *handle, int nblocks);
|
||||
|
||||
|
||||
/* ocfs2_inode */
|
||||
int ocfs2_journal_access_di(handle_t *handle, struct inode *inode,
|
||||
int ocfs2_journal_access_di(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh, int type);
|
||||
/* ocfs2_extent_block */
|
||||
int ocfs2_journal_access_eb(handle_t *handle, struct inode *inode,
|
||||
int ocfs2_journal_access_eb(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh, int type);
|
||||
/* ocfs2_refcount_block */
|
||||
int ocfs2_journal_access_rb(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh, int type);
|
||||
/* ocfs2_group_desc */
|
||||
int ocfs2_journal_access_gd(handle_t *handle, struct inode *inode,
|
||||
int ocfs2_journal_access_gd(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh, int type);
|
||||
/* ocfs2_xattr_block */
|
||||
int ocfs2_journal_access_xb(handle_t *handle, struct inode *inode,
|
||||
int ocfs2_journal_access_xb(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh, int type);
|
||||
/* quota blocks */
|
||||
int ocfs2_journal_access_dq(handle_t *handle, struct inode *inode,
|
||||
int ocfs2_journal_access_dq(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh, int type);
|
||||
/* dirblock */
|
||||
int ocfs2_journal_access_db(handle_t *handle, struct inode *inode,
|
||||
int ocfs2_journal_access_db(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh, int type);
|
||||
/* ocfs2_dx_root_block */
|
||||
int ocfs2_journal_access_dr(handle_t *handle, struct inode *inode,
|
||||
int ocfs2_journal_access_dr(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh, int type);
|
||||
/* ocfs2_dx_leaf */
|
||||
int ocfs2_journal_access_dl(handle_t *handle, struct inode *inode,
|
||||
int ocfs2_journal_access_dl(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh, int type);
|
||||
/* Anything that has no ecc */
|
||||
int ocfs2_journal_access(handle_t *handle, struct inode *inode,
|
||||
int ocfs2_journal_access(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh, int type);
|
||||
|
||||
/*
|
||||
@ -477,6 +490,23 @@ static inline int ocfs2_calc_dxi_expand_credits(struct super_block *sb)
|
||||
return credits;
|
||||
}
|
||||
|
||||
/* inode update, new refcount block and its allocation credits. */
|
||||
#define OCFS2_REFCOUNT_TREE_CREATE_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 1 \
|
||||
+ OCFS2_SUBALLOC_ALLOC)
|
||||
|
||||
/* inode and the refcount block update. */
|
||||
#define OCFS2_REFCOUNT_TREE_SET_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 1)
|
||||
|
||||
/*
|
||||
* inode and the refcount block update.
|
||||
* It doesn't include the credits for sub alloc change.
|
||||
* So if we need to free the bit, OCFS2_SUBALLOC_FREE needs to be added.
|
||||
*/
|
||||
#define OCFS2_REFCOUNT_TREE_REMOVE_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 1)
|
||||
|
||||
/* 2 metadata alloc, 2 new blocks and root refcount block */
|
||||
#define OCFS2_EXPAND_REFCOUNT_TREE_CREDITS (OCFS2_SUBALLOC_ALLOC * 2 + 3)
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
@ -297,8 +297,8 @@ void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb)
|
||||
}
|
||||
memcpy(alloc_copy, alloc, bh->b_size);
|
||||
|
||||
status = ocfs2_journal_access_di(handle, local_alloc_inode, bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
status = ocfs2_journal_access_di(handle, INODE_CACHE(local_alloc_inode),
|
||||
bh, OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
goto out_commit;
|
||||
@ -392,7 +392,7 @@ int ocfs2_begin_local_alloc_recovery(struct ocfs2_super *osb,
|
||||
ocfs2_clear_local_alloc(alloc);
|
||||
|
||||
ocfs2_compute_meta_ecc(osb->sb, alloc_bh->b_data, &alloc->i_check);
|
||||
status = ocfs2_write_block(osb, alloc_bh, inode);
|
||||
status = ocfs2_write_block(osb, alloc_bh, INODE_CACHE(inode));
|
||||
if (status < 0)
|
||||
mlog_errno(status);
|
||||
|
||||
@ -678,7 +678,8 @@ int ocfs2_claim_local_alloc_bits(struct ocfs2_super *osb,
|
||||
* delete bits from it! */
|
||||
*num_bits = bits_wanted;
|
||||
|
||||
status = ocfs2_journal_access_di(handle, local_alloc_inode,
|
||||
status = ocfs2_journal_access_di(handle,
|
||||
INODE_CACHE(local_alloc_inode),
|
||||
osb->local_alloc_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (status < 0) {
|
||||
@ -1156,7 +1157,8 @@ static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb,
|
||||
}
|
||||
memcpy(alloc_copy, alloc, osb->local_alloc_bh->b_size);
|
||||
|
||||
status = ocfs2_journal_access_di(handle, local_alloc_inode,
|
||||
status = ocfs2_journal_access_di(handle,
|
||||
INODE_CACHE(local_alloc_inode),
|
||||
osb->local_alloc_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (status < 0) {
|
||||
|
341
fs/ocfs2/namei.c
341
fs/ocfs2/namei.c
@ -69,7 +69,6 @@
|
||||
static int ocfs2_mknod_locked(struct ocfs2_super *osb,
|
||||
struct inode *dir,
|
||||
struct inode *inode,
|
||||
struct dentry *dentry,
|
||||
dev_t dev,
|
||||
struct buffer_head **new_fe_bh,
|
||||
struct buffer_head *parent_fe_bh,
|
||||
@ -78,7 +77,7 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb,
|
||||
|
||||
static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb,
|
||||
struct inode **ret_orphan_dir,
|
||||
struct inode *inode,
|
||||
u64 blkno,
|
||||
char *name,
|
||||
struct ocfs2_dir_lookup_result *lookup);
|
||||
|
||||
@ -358,8 +357,12 @@ static int ocfs2_mknod(struct inode *dir,
|
||||
}
|
||||
did_quota_inode = 1;
|
||||
|
||||
mlog_entry("(0x%p, 0x%p, %d, %lu, '%.*s')\n", dir, dentry,
|
||||
inode->i_mode, (unsigned long)dev, dentry->d_name.len,
|
||||
dentry->d_name.name);
|
||||
|
||||
/* do the real work now. */
|
||||
status = ocfs2_mknod_locked(osb, dir, inode, dentry, dev,
|
||||
status = ocfs2_mknod_locked(osb, dir, inode, dev,
|
||||
&new_fe_bh, parent_fe_bh, handle,
|
||||
inode_ac);
|
||||
if (status < 0) {
|
||||
@ -375,7 +378,8 @@ static int ocfs2_mknod(struct inode *dir,
|
||||
goto leave;
|
||||
}
|
||||
|
||||
status = ocfs2_journal_access_di(handle, dir, parent_fe_bh,
|
||||
status = ocfs2_journal_access_di(handle, INODE_CACHE(dir),
|
||||
parent_fe_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
@ -465,7 +469,6 @@ leave:
|
||||
static int ocfs2_mknod_locked(struct ocfs2_super *osb,
|
||||
struct inode *dir,
|
||||
struct inode *inode,
|
||||
struct dentry *dentry,
|
||||
dev_t dev,
|
||||
struct buffer_head **new_fe_bh,
|
||||
struct buffer_head *parent_fe_bh,
|
||||
@ -479,10 +482,6 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb,
|
||||
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,
|
||||
dentry->d_name.name);
|
||||
|
||||
*new_fe_bh = NULL;
|
||||
|
||||
status = ocfs2_claim_new_inode(osb, handle, dir, parent_fe_bh,
|
||||
@ -507,9 +506,10 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb,
|
||||
mlog_errno(status);
|
||||
goto leave;
|
||||
}
|
||||
ocfs2_set_new_buffer_uptodate(inode, *new_fe_bh);
|
||||
ocfs2_set_new_buffer_uptodate(INODE_CACHE(inode), *new_fe_bh);
|
||||
|
||||
status = ocfs2_journal_access_di(handle, inode, *new_fe_bh,
|
||||
status = ocfs2_journal_access_di(handle, INODE_CACHE(inode),
|
||||
*new_fe_bh,
|
||||
OCFS2_JOURNAL_ACCESS_CREATE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
@ -565,7 +565,7 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb,
|
||||
}
|
||||
|
||||
ocfs2_populate_inode(inode, fe, 1);
|
||||
ocfs2_inode_set_new(osb, inode);
|
||||
ocfs2_ci_set_new(osb, INODE_CACHE(inode));
|
||||
if (!ocfs2_mount_local(osb)) {
|
||||
status = ocfs2_create_new_inode_locks(inode);
|
||||
if (status < 0)
|
||||
@ -682,7 +682,7 @@ static int ocfs2_link(struct dentry *old_dentry,
|
||||
goto out_unlock_inode;
|
||||
}
|
||||
|
||||
err = ocfs2_journal_access_di(handle, inode, fe_bh,
|
||||
err = ocfs2_journal_access_di(handle, INODE_CACHE(inode), fe_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (err < 0) {
|
||||
mlog_errno(err);
|
||||
@ -850,7 +850,8 @@ static int ocfs2_unlink(struct inode *dir,
|
||||
}
|
||||
|
||||
if (inode_is_unlinkable(inode)) {
|
||||
status = ocfs2_prepare_orphan_dir(osb, &orphan_dir, inode,
|
||||
status = ocfs2_prepare_orphan_dir(osb, &orphan_dir,
|
||||
OCFS2_I(inode)->ip_blkno,
|
||||
orphan_name, &orphan_insert);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
@ -866,7 +867,7 @@ static int ocfs2_unlink(struct inode *dir,
|
||||
goto leave;
|
||||
}
|
||||
|
||||
status = ocfs2_journal_access_di(handle, inode, fe_bh,
|
||||
status = ocfs2_journal_access_di(handle, INODE_CACHE(inode), fe_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
@ -1241,9 +1242,8 @@ static int ocfs2_rename(struct inode *old_dir,
|
||||
|
||||
if (S_ISDIR(new_inode->i_mode) || (new_inode->i_nlink == 1)) {
|
||||
status = ocfs2_prepare_orphan_dir(osb, &orphan_dir,
|
||||
new_inode,
|
||||
orphan_name,
|
||||
&orphan_insert);
|
||||
OCFS2_I(new_inode)->ip_blkno,
|
||||
orphan_name, &orphan_insert);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
goto bail;
|
||||
@ -1284,7 +1284,8 @@ static int ocfs2_rename(struct inode *old_dir,
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
status = ocfs2_journal_access_di(handle, new_inode, newfe_bh,
|
||||
status = ocfs2_journal_access_di(handle, INODE_CACHE(new_inode),
|
||||
newfe_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
@ -1331,7 +1332,8 @@ static int ocfs2_rename(struct inode *old_dir,
|
||||
old_inode->i_ctime = CURRENT_TIME;
|
||||
mark_inode_dirty(old_inode);
|
||||
|
||||
status = ocfs2_journal_access_di(handle, old_inode, old_inode_bh,
|
||||
status = ocfs2_journal_access_di(handle, INODE_CACHE(old_inode),
|
||||
old_inode_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (status >= 0) {
|
||||
old_di = (struct ocfs2_dinode *) old_inode_bh->b_data;
|
||||
@ -1407,9 +1409,10 @@ static int ocfs2_rename(struct inode *old_dir,
|
||||
(int)old_dir_nlink, old_dir->i_nlink);
|
||||
} else {
|
||||
struct ocfs2_dinode *fe;
|
||||
status = ocfs2_journal_access_di(handle, old_dir,
|
||||
old_dir_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
status = ocfs2_journal_access_di(handle,
|
||||
INODE_CACHE(old_dir),
|
||||
old_dir_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
fe = (struct ocfs2_dinode *) old_dir_bh->b_data;
|
||||
ocfs2_set_links_count(fe, old_dir->i_nlink);
|
||||
status = ocfs2_journal_dirty(handle, old_dir_bh);
|
||||
@ -1527,9 +1530,11 @@ static int ocfs2_create_symlink_data(struct ocfs2_super *osb,
|
||||
mlog_errno(status);
|
||||
goto bail;
|
||||
}
|
||||
ocfs2_set_new_buffer_uptodate(inode, bhs[virtual]);
|
||||
ocfs2_set_new_buffer_uptodate(INODE_CACHE(inode),
|
||||
bhs[virtual]);
|
||||
|
||||
status = ocfs2_journal_access(handle, inode, bhs[virtual],
|
||||
status = ocfs2_journal_access(handle, INODE_CACHE(inode),
|
||||
bhs[virtual],
|
||||
OCFS2_JOURNAL_ACCESS_CREATE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
@ -1692,7 +1697,11 @@ static int ocfs2_symlink(struct inode *dir,
|
||||
}
|
||||
did_quota_inode = 1;
|
||||
|
||||
status = ocfs2_mknod_locked(osb, dir, inode, dentry,
|
||||
mlog_entry("(0x%p, 0x%p, %d, '%.*s')\n", dir, dentry,
|
||||
inode->i_mode, dentry->d_name.len,
|
||||
dentry->d_name.name);
|
||||
|
||||
status = ocfs2_mknod_locked(osb, dir, inode,
|
||||
0, &new_fe_bh, parent_fe_bh, handle,
|
||||
inode_ac);
|
||||
if (status < 0) {
|
||||
@ -1842,7 +1851,7 @@ bail:
|
||||
|
||||
static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb,
|
||||
struct inode **ret_orphan_dir,
|
||||
struct inode *inode,
|
||||
u64 blkno,
|
||||
char *name,
|
||||
struct ocfs2_dir_lookup_result *lookup)
|
||||
{
|
||||
@ -1850,7 +1859,7 @@ static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb,
|
||||
struct buffer_head *orphan_dir_bh = NULL;
|
||||
int status = 0;
|
||||
|
||||
status = ocfs2_blkno_stringify(OCFS2_I(inode)->ip_blkno, name);
|
||||
status = ocfs2_blkno_stringify(blkno, name);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
return status;
|
||||
@ -1917,7 +1926,9 @@ static int ocfs2_orphan_add(struct ocfs2_super *osb,
|
||||
goto leave;
|
||||
}
|
||||
|
||||
status = ocfs2_journal_access_di(handle, orphan_dir_inode, orphan_dir_bh,
|
||||
status = ocfs2_journal_access_di(handle,
|
||||
INODE_CACHE(orphan_dir_inode),
|
||||
orphan_dir_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
@ -2002,7 +2013,9 @@ int ocfs2_orphan_del(struct ocfs2_super *osb,
|
||||
goto leave;
|
||||
}
|
||||
|
||||
status = ocfs2_journal_access_di(handle,orphan_dir_inode, orphan_dir_bh,
|
||||
status = ocfs2_journal_access_di(handle,
|
||||
INODE_CACHE(orphan_dir_inode),
|
||||
orphan_dir_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
@ -2028,6 +2041,274 @@ leave:
|
||||
return status;
|
||||
}
|
||||
|
||||
int ocfs2_create_inode_in_orphan(struct inode *dir,
|
||||
int mode,
|
||||
struct inode **new_inode)
|
||||
{
|
||||
int status, did_quota_inode = 0;
|
||||
struct inode *inode = NULL;
|
||||
struct inode *orphan_dir = NULL;
|
||||
struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
|
||||
struct ocfs2_dinode *di = NULL;
|
||||
handle_t *handle = NULL;
|
||||
char orphan_name[OCFS2_ORPHAN_NAMELEN + 1];
|
||||
struct buffer_head *parent_di_bh = NULL;
|
||||
struct buffer_head *new_di_bh = NULL;
|
||||
struct ocfs2_alloc_context *inode_ac = NULL;
|
||||
struct ocfs2_dir_lookup_result orphan_insert = { NULL, };
|
||||
|
||||
status = ocfs2_inode_lock(dir, &parent_di_bh, 1);
|
||||
if (status < 0) {
|
||||
if (status != -ENOENT)
|
||||
mlog_errno(status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* We give the orphan dir the root blkno to fake an orphan name,
|
||||
* and allocate enough space for our insertion.
|
||||
*/
|
||||
status = ocfs2_prepare_orphan_dir(osb, &orphan_dir,
|
||||
osb->root_blkno,
|
||||
orphan_name, &orphan_insert);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* reserve an inode spot */
|
||||
status = ocfs2_reserve_new_inode(osb, &inode_ac);
|
||||
if (status < 0) {
|
||||
if (status != -ENOSPC)
|
||||
mlog_errno(status);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
inode = ocfs2_get_init_inode(dir, mode);
|
||||
if (!inode) {
|
||||
status = -ENOMEM;
|
||||
mlog_errno(status);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
handle = ocfs2_start_trans(osb, ocfs2_mknod_credits(osb->sb, 0, 0));
|
||||
if (IS_ERR(handle)) {
|
||||
status = PTR_ERR(handle);
|
||||
handle = NULL;
|
||||
mlog_errno(status);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* We don't use standard VFS wrapper because we don't want vfs_dq_init
|
||||
* to be called. */
|
||||
if (sb_any_quota_active(osb->sb) &&
|
||||
osb->sb->dq_op->alloc_inode(inode, 1) == NO_QUOTA) {
|
||||
status = -EDQUOT;
|
||||
goto leave;
|
||||
}
|
||||
did_quota_inode = 1;
|
||||
|
||||
/* do the real work now. */
|
||||
status = ocfs2_mknod_locked(osb, dir, inode,
|
||||
0, &new_di_bh, parent_di_bh, handle,
|
||||
inode_ac);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
status = ocfs2_blkno_stringify(OCFS2_I(inode)->ip_blkno, orphan_name);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
di = (struct ocfs2_dinode *)new_di_bh->b_data;
|
||||
status = ocfs2_orphan_add(osb, handle, inode, di, orphan_name,
|
||||
&orphan_insert, orphan_dir);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* get open lock so that only nodes can't remove it from orphan dir. */
|
||||
status = ocfs2_open_lock(inode);
|
||||
if (status < 0)
|
||||
mlog_errno(status);
|
||||
|
||||
leave:
|
||||
if (status < 0 && did_quota_inode)
|
||||
vfs_dq_free_inode(inode);
|
||||
if (handle)
|
||||
ocfs2_commit_trans(osb, handle);
|
||||
|
||||
if (orphan_dir) {
|
||||
/* This was locked for us in ocfs2_prepare_orphan_dir() */
|
||||
ocfs2_inode_unlock(orphan_dir, 1);
|
||||
mutex_unlock(&orphan_dir->i_mutex);
|
||||
iput(orphan_dir);
|
||||
}
|
||||
|
||||
if (status == -ENOSPC)
|
||||
mlog(0, "Disk is full\n");
|
||||
|
||||
if ((status < 0) && inode) {
|
||||
clear_nlink(inode);
|
||||
iput(inode);
|
||||
}
|
||||
|
||||
if (inode_ac)
|
||||
ocfs2_free_alloc_context(inode_ac);
|
||||
|
||||
brelse(new_di_bh);
|
||||
|
||||
if (!status)
|
||||
*new_inode = inode;
|
||||
|
||||
ocfs2_free_dir_lookup_result(&orphan_insert);
|
||||
|
||||
ocfs2_inode_unlock(dir, 1);
|
||||
brelse(parent_di_bh);
|
||||
return status;
|
||||
}
|
||||
|
||||
int ocfs2_mv_orphaned_inode_to_new(struct inode *dir,
|
||||
struct inode *inode,
|
||||
struct dentry *dentry)
|
||||
{
|
||||
int status = 0;
|
||||
struct buffer_head *parent_di_bh = NULL;
|
||||
handle_t *handle = NULL;
|
||||
struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
|
||||
struct ocfs2_dinode *dir_di, *di;
|
||||
struct inode *orphan_dir_inode = NULL;
|
||||
struct buffer_head *orphan_dir_bh = NULL;
|
||||
struct buffer_head *di_bh = NULL;
|
||||
struct ocfs2_dir_lookup_result lookup = { NULL, };
|
||||
|
||||
mlog_entry("(0x%p, 0x%p, %.*s')\n", dir, dentry,
|
||||
dentry->d_name.len, dentry->d_name.name);
|
||||
|
||||
status = ocfs2_inode_lock(dir, &parent_di_bh, 1);
|
||||
if (status < 0) {
|
||||
if (status != -ENOENT)
|
||||
mlog_errno(status);
|
||||
return status;
|
||||
}
|
||||
|
||||
dir_di = (struct ocfs2_dinode *) parent_di_bh->b_data;
|
||||
if (!dir_di->i_links_count) {
|
||||
/* can't make a file in a deleted directory. */
|
||||
status = -ENOENT;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
status = ocfs2_check_dir_for_entry(dir, dentry->d_name.name,
|
||||
dentry->d_name.len);
|
||||
if (status)
|
||||
goto leave;
|
||||
|
||||
/* get a spot inside the dir. */
|
||||
status = ocfs2_prepare_dir_for_insert(osb, dir, parent_di_bh,
|
||||
dentry->d_name.name,
|
||||
dentry->d_name.len, &lookup);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
orphan_dir_inode = ocfs2_get_system_file_inode(osb,
|
||||
ORPHAN_DIR_SYSTEM_INODE,
|
||||
osb->slot_num);
|
||||
if (!orphan_dir_inode) {
|
||||
status = -EEXIST;
|
||||
mlog_errno(status);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
mutex_lock(&orphan_dir_inode->i_mutex);
|
||||
|
||||
status = ocfs2_inode_lock(orphan_dir_inode, &orphan_dir_bh, 1);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
mutex_unlock(&orphan_dir_inode->i_mutex);
|
||||
iput(orphan_dir_inode);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
status = ocfs2_read_inode_block(inode, &di_bh);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
goto orphan_unlock;
|
||||
}
|
||||
|
||||
handle = ocfs2_start_trans(osb, ocfs2_rename_credits(osb->sb));
|
||||
if (IS_ERR(handle)) {
|
||||
status = PTR_ERR(handle);
|
||||
handle = NULL;
|
||||
mlog_errno(status);
|
||||
goto orphan_unlock;
|
||||
}
|
||||
|
||||
status = ocfs2_journal_access_di(handle, INODE_CACHE(inode),
|
||||
di_bh, OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
goto out_commit;
|
||||
}
|
||||
|
||||
status = ocfs2_orphan_del(osb, handle, orphan_dir_inode, inode,
|
||||
orphan_dir_bh);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
goto out_commit;
|
||||
}
|
||||
|
||||
di = (struct ocfs2_dinode *)di_bh->b_data;
|
||||
le32_add_cpu(&di->i_flags, -OCFS2_ORPHANED_FL);
|
||||
di->i_orphaned_slot = 0;
|
||||
ocfs2_journal_dirty(handle, di_bh);
|
||||
|
||||
status = ocfs2_add_entry(handle, dentry, inode,
|
||||
OCFS2_I(inode)->ip_blkno, parent_di_bh,
|
||||
&lookup);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
goto out_commit;
|
||||
}
|
||||
|
||||
status = ocfs2_dentry_attach_lock(dentry, inode,
|
||||
OCFS2_I(dir)->ip_blkno);
|
||||
if (status) {
|
||||
mlog_errno(status);
|
||||
goto out_commit;
|
||||
}
|
||||
|
||||
insert_inode_hash(inode);
|
||||
dentry->d_op = &ocfs2_dentry_ops;
|
||||
d_instantiate(dentry, inode);
|
||||
status = 0;
|
||||
out_commit:
|
||||
ocfs2_commit_trans(osb, handle);
|
||||
orphan_unlock:
|
||||
ocfs2_inode_unlock(orphan_dir_inode, 1);
|
||||
mutex_unlock(&orphan_dir_inode->i_mutex);
|
||||
iput(orphan_dir_inode);
|
||||
leave:
|
||||
|
||||
ocfs2_inode_unlock(dir, 1);
|
||||
|
||||
brelse(di_bh);
|
||||
brelse(parent_di_bh);
|
||||
brelse(orphan_dir_bh);
|
||||
|
||||
ocfs2_free_dir_lookup_result(&lookup);
|
||||
|
||||
mlog_exit(status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
const struct inode_operations ocfs2_dir_iops = {
|
||||
.create = ocfs2_create,
|
||||
.lookup = ocfs2_lookup,
|
||||
|
@ -35,5 +35,11 @@ int ocfs2_orphan_del(struct ocfs2_super *osb,
|
||||
struct inode *orphan_dir_inode,
|
||||
struct inode *inode,
|
||||
struct buffer_head *orphan_dir_bh);
|
||||
int ocfs2_create_inode_in_orphan(struct inode *dir,
|
||||
int mode,
|
||||
struct inode **new_inode);
|
||||
int ocfs2_mv_orphaned_inode_to_new(struct inode *dir,
|
||||
struct inode *new_inode,
|
||||
struct dentry *new_dentry);
|
||||
|
||||
#endif /* OCFS2_NAMEI_H */
|
||||
|
@ -51,20 +51,51 @@
|
||||
/* For struct ocfs2_blockcheck_stats */
|
||||
#include "blockcheck.h"
|
||||
|
||||
|
||||
/* Caching of metadata buffers */
|
||||
|
||||
/* Most user visible OCFS2 inodes will have very few pieces of
|
||||
* metadata, but larger files (including bitmaps, etc) must be taken
|
||||
* into account when designing an access scheme. We allow a small
|
||||
* amount of inlined blocks to be stored on an array and grow the
|
||||
* structure into a rb tree when necessary. */
|
||||
#define OCFS2_INODE_MAX_CACHE_ARRAY 2
|
||||
#define OCFS2_CACHE_INFO_MAX_ARRAY 2
|
||||
|
||||
/* Flags for ocfs2_caching_info */
|
||||
|
||||
enum ocfs2_caching_info_flags {
|
||||
/* Indicates that the metadata cache is using the inline array */
|
||||
OCFS2_CACHE_FL_INLINE = 1<<1,
|
||||
};
|
||||
|
||||
struct ocfs2_caching_operations;
|
||||
struct ocfs2_caching_info {
|
||||
/*
|
||||
* The parent structure provides the locks, but because the
|
||||
* parent structure can differ, it provides locking operations
|
||||
* to struct ocfs2_caching_info.
|
||||
*/
|
||||
const struct ocfs2_caching_operations *ci_ops;
|
||||
|
||||
/* next two are protected by trans_inc_lock */
|
||||
/* which transaction were we created on? Zero if none. */
|
||||
unsigned long ci_created_trans;
|
||||
/* last transaction we were a part of. */
|
||||
unsigned long ci_last_trans;
|
||||
|
||||
/* Cache structures */
|
||||
unsigned int ci_flags;
|
||||
unsigned int ci_num_cached;
|
||||
union {
|
||||
sector_t ci_array[OCFS2_INODE_MAX_CACHE_ARRAY];
|
||||
sector_t ci_array[OCFS2_CACHE_INFO_MAX_ARRAY];
|
||||
struct rb_root ci_tree;
|
||||
} ci_cache;
|
||||
};
|
||||
/*
|
||||
* Need this prototype here instead of in uptodate.h because journal.h
|
||||
* uses it.
|
||||
*/
|
||||
struct super_block *ocfs2_metadata_cache_get_super(struct ocfs2_caching_info *ci);
|
||||
|
||||
/* this limits us to 256 nodes
|
||||
* if we need more, we can do a kmalloc for the map */
|
||||
@ -377,12 +408,17 @@ struct ocfs2_super
|
||||
|
||||
/* the group we used to allocate inodes. */
|
||||
u64 osb_inode_alloc_group;
|
||||
|
||||
/* rb tree root for refcount lock. */
|
||||
struct rb_root osb_rf_lock_tree;
|
||||
struct ocfs2_refcount_tree *osb_ref_tree_lru;
|
||||
};
|
||||
|
||||
#define OCFS2_SB(sb) ((struct ocfs2_super *)(sb)->s_fs_info)
|
||||
|
||||
/* Useful typedef for passing around journal access functions */
|
||||
typedef int (*ocfs2_journal_access_func)(handle_t *handle, struct inode *inode,
|
||||
typedef int (*ocfs2_journal_access_func)(handle_t *handle,
|
||||
struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh, int type);
|
||||
|
||||
static inline int ocfs2_should_order_data(struct inode *inode)
|
||||
@ -480,6 +516,13 @@ static inline void ocfs2_add_links_count(struct ocfs2_dinode *di, int n)
|
||||
ocfs2_set_links_count(di, links);
|
||||
}
|
||||
|
||||
static inline int ocfs2_refcount_tree(struct ocfs2_super *osb)
|
||||
{
|
||||
if (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_REFCOUNT_TREE)
|
||||
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
|
||||
@ -578,6 +621,9 @@ static inline int ocfs2_uses_extended_slot_map(struct ocfs2_super *osb)
|
||||
#define OCFS2_IS_VALID_DX_LEAF(ptr) \
|
||||
(!strcmp((ptr)->dl_signature, OCFS2_DX_LEAF_SIGNATURE))
|
||||
|
||||
#define OCFS2_IS_VALID_REFCOUNT_BLOCK(ptr) \
|
||||
(!strcmp((ptr)->rf_signature, OCFS2_REFCOUNT_BLOCK_SIGNATURE))
|
||||
|
||||
static inline unsigned long ino_from_blkno(struct super_block *sb,
|
||||
u64 blkno)
|
||||
{
|
||||
|
@ -68,6 +68,7 @@
|
||||
#define OCFS2_DIR_TRAILER_SIGNATURE "DIRTRL1"
|
||||
#define OCFS2_DX_ROOT_SIGNATURE "DXDIR01"
|
||||
#define OCFS2_DX_LEAF_SIGNATURE "DXLEAF1"
|
||||
#define OCFS2_REFCOUNT_BLOCK_SIGNATURE "REFCNT1"
|
||||
|
||||
/* Compatibility flags */
|
||||
#define OCFS2_HAS_COMPAT_FEATURE(sb,mask) \
|
||||
@ -98,7 +99,8 @@
|
||||
| OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK \
|
||||
| OCFS2_FEATURE_INCOMPAT_XATTR \
|
||||
| OCFS2_FEATURE_INCOMPAT_META_ECC \
|
||||
| OCFS2_FEATURE_INCOMPAT_INDEXED_DIRS)
|
||||
| OCFS2_FEATURE_INCOMPAT_INDEXED_DIRS \
|
||||
| OCFS2_FEATURE_INCOMPAT_REFCOUNT_TREE)
|
||||
#define OCFS2_FEATURE_RO_COMPAT_SUPP (OCFS2_FEATURE_RO_COMPAT_UNWRITTEN \
|
||||
| OCFS2_FEATURE_RO_COMPAT_USRQUOTA \
|
||||
| OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)
|
||||
@ -160,6 +162,9 @@
|
||||
/* Metadata checksum and error correction */
|
||||
#define OCFS2_FEATURE_INCOMPAT_META_ECC 0x0800
|
||||
|
||||
/* Refcount tree support */
|
||||
#define OCFS2_FEATURE_INCOMPAT_REFCOUNT_TREE 0x1000
|
||||
|
||||
/*
|
||||
* backup superblock flag is used to indicate that this volume
|
||||
* has backup superblocks.
|
||||
@ -223,6 +228,7 @@
|
||||
#define OCFS2_HAS_XATTR_FL (0x0002)
|
||||
#define OCFS2_INLINE_XATTR_FL (0x0004)
|
||||
#define OCFS2_INDEXED_DIR_FL (0x0008)
|
||||
#define OCFS2_HAS_REFCOUNT_FL (0x0010)
|
||||
|
||||
/* Inode attributes, keep in sync with EXT2 */
|
||||
#define OCFS2_SECRM_FL (0x00000001) /* Secure deletion */
|
||||
@ -241,8 +247,11 @@
|
||||
/*
|
||||
* Extent record flags (e_node.leaf.flags)
|
||||
*/
|
||||
#define OCFS2_EXT_UNWRITTEN (0x01) /* Extent is allocated but
|
||||
* unwritten */
|
||||
#define OCFS2_EXT_UNWRITTEN (0x01) /* Extent is allocated but
|
||||
* unwritten */
|
||||
#define OCFS2_EXT_REFCOUNTED (0x02) /* Extent is reference
|
||||
* counted in an associated
|
||||
* refcount tree */
|
||||
|
||||
/*
|
||||
* ioctl commands
|
||||
@ -292,6 +301,15 @@ struct ocfs2_new_group_input {
|
||||
#define OCFS2_IOC_GROUP_ADD _IOW('o', 2,struct ocfs2_new_group_input)
|
||||
#define OCFS2_IOC_GROUP_ADD64 _IOW('o', 3,struct ocfs2_new_group_input)
|
||||
|
||||
/* Used to pass 2 file names to reflink. */
|
||||
struct reflink_arguments {
|
||||
__u64 old_path;
|
||||
__u64 new_path;
|
||||
__u64 preserve;
|
||||
};
|
||||
#define OCFS2_IOC_REFLINK _IOW('o', 4, struct reflink_arguments)
|
||||
|
||||
|
||||
/*
|
||||
* Journal Flags (ocfs2_dinode.id1.journal1.i_flags)
|
||||
*/
|
||||
@ -717,7 +735,8 @@ struct ocfs2_dinode {
|
||||
__le64 i_xattr_loc;
|
||||
/*80*/ struct ocfs2_block_check i_check; /* Error checking */
|
||||
/*88*/ __le64 i_dx_root; /* Pointer to dir index root block */
|
||||
__le64 i_reserved2[5];
|
||||
/*90*/ __le64 i_refcount_loc;
|
||||
__le64 i_reserved2[4];
|
||||
/*B8*/ union {
|
||||
__le64 i_pad1; /* Generic way to refer to this
|
||||
64bit union */
|
||||
@ -901,6 +920,60 @@ struct ocfs2_group_desc
|
||||
/*40*/ __u8 bg_bitmap[0];
|
||||
};
|
||||
|
||||
struct ocfs2_refcount_rec {
|
||||
/*00*/ __le64 r_cpos; /* Physical offset, in clusters */
|
||||
__le32 r_clusters; /* Clusters covered by this extent */
|
||||
__le32 r_refcount; /* Reference count of this extent */
|
||||
/*10*/
|
||||
};
|
||||
#define OCFS2_32BIT_POS_MASK (0xffffffffULL)
|
||||
|
||||
#define OCFS2_REFCOUNT_LEAF_FL (0x00000001)
|
||||
#define OCFS2_REFCOUNT_TREE_FL (0x00000002)
|
||||
|
||||
struct ocfs2_refcount_list {
|
||||
/*00*/ __le16 rl_count; /* Maximum number of entries possible
|
||||
in rl_records */
|
||||
__le16 rl_used; /* Current number of used records */
|
||||
__le32 rl_reserved2;
|
||||
__le64 rl_reserved1; /* Pad to sizeof(ocfs2_refcount_record) */
|
||||
/*10*/ struct ocfs2_refcount_rec rl_recs[0]; /* Refcount records */
|
||||
};
|
||||
|
||||
|
||||
struct ocfs2_refcount_block {
|
||||
/*00*/ __u8 rf_signature[8]; /* Signature for verification */
|
||||
__le16 rf_suballoc_slot; /* Slot suballocator this block
|
||||
belongs to */
|
||||
__le16 rf_suballoc_bit; /* Bit offset in suballocator
|
||||
block group */
|
||||
__le32 rf_fs_generation; /* Must match superblock */
|
||||
/*10*/ __le64 rf_blkno; /* Offset on disk, in blocks */
|
||||
__le64 rf_parent; /* Parent block, only valid if
|
||||
OCFS2_REFCOUNT_LEAF_FL is set in
|
||||
rf_flags */
|
||||
/*20*/ struct ocfs2_block_check rf_check; /* Error checking */
|
||||
__le64 rf_last_eb_blk; /* Pointer to last extent block */
|
||||
/*30*/ __le32 rf_count; /* Number of inodes sharing this
|
||||
refcount tree */
|
||||
__le32 rf_flags; /* See the flags above */
|
||||
__le32 rf_clusters; /* clusters covered by refcount tree. */
|
||||
__le32 rf_cpos; /* cluster offset in refcount tree.*/
|
||||
/*40*/ __le32 rf_generation; /* generation number. all be the same
|
||||
* for the same refcount tree. */
|
||||
__le32 rf_reserved0;
|
||||
__le64 rf_reserved1[7];
|
||||
/*80*/ union {
|
||||
struct ocfs2_refcount_list rf_records; /* List of refcount
|
||||
records */
|
||||
struct ocfs2_extent_list rf_list; /* Extent record list,
|
||||
only valid if
|
||||
OCFS2_REFCOUNT_TREE_FL
|
||||
is set in rf_flags */
|
||||
};
|
||||
/* Actual on-disk size is one block */
|
||||
};
|
||||
|
||||
/*
|
||||
* On disk extended attribute structure for OCFS2.
|
||||
*/
|
||||
@ -1312,6 +1385,32 @@ static inline u16 ocfs2_xattr_recs_per_xb(struct super_block *sb)
|
||||
|
||||
return size / sizeof(struct ocfs2_extent_rec);
|
||||
}
|
||||
|
||||
static inline u16 ocfs2_extent_recs_per_rb(struct super_block *sb)
|
||||
{
|
||||
int size;
|
||||
|
||||
size = sb->s_blocksize -
|
||||
offsetof(struct ocfs2_refcount_block, rf_list.l_recs);
|
||||
|
||||
return size / sizeof(struct ocfs2_extent_rec);
|
||||
}
|
||||
|
||||
static inline u16 ocfs2_refcount_recs_per_rb(struct super_block *sb)
|
||||
{
|
||||
int size;
|
||||
|
||||
size = sb->s_blocksize -
|
||||
offsetof(struct ocfs2_refcount_block, rf_records.rl_recs);
|
||||
|
||||
return size / sizeof(struct ocfs2_refcount_rec);
|
||||
}
|
||||
|
||||
static inline u32
|
||||
ocfs2_get_ref_rec_low_cpos(const struct ocfs2_refcount_rec *rec)
|
||||
{
|
||||
return le64_to_cpu(rec->r_cpos) & OCFS2_32BIT_POS_MASK;
|
||||
}
|
||||
#else
|
||||
static inline int ocfs2_fast_symlink_chars(int blocksize)
|
||||
{
|
||||
|
@ -49,6 +49,7 @@ enum ocfs2_lock_type {
|
||||
OCFS2_LOCK_TYPE_QINFO,
|
||||
OCFS2_LOCK_TYPE_NFS_SYNC,
|
||||
OCFS2_LOCK_TYPE_ORPHAN_SCAN,
|
||||
OCFS2_LOCK_TYPE_REFCOUNT,
|
||||
OCFS2_NUM_LOCK_TYPES
|
||||
};
|
||||
|
||||
@ -89,6 +90,9 @@ static inline char ocfs2_lock_type_char(enum ocfs2_lock_type type)
|
||||
case OCFS2_LOCK_TYPE_ORPHAN_SCAN:
|
||||
c = 'P';
|
||||
break;
|
||||
case OCFS2_LOCK_TYPE_REFCOUNT:
|
||||
c = 'T';
|
||||
break;
|
||||
default:
|
||||
c = '\0';
|
||||
}
|
||||
@ -110,6 +114,7 @@ static char *ocfs2_lock_type_strings[] = {
|
||||
[OCFS2_LOCK_TYPE_QINFO] = "Quota",
|
||||
[OCFS2_LOCK_TYPE_NFS_SYNC] = "NFSSync",
|
||||
[OCFS2_LOCK_TYPE_ORPHAN_SCAN] = "OrphanScan",
|
||||
[OCFS2_LOCK_TYPE_REFCOUNT] = "Refcount",
|
||||
};
|
||||
|
||||
static inline const char *ocfs2_lock_type_string(enum ocfs2_lock_type type)
|
||||
|
@ -253,8 +253,9 @@ ssize_t ocfs2_quota_write(struct super_block *sb, int type,
|
||||
flush_dcache_page(bh->b_page);
|
||||
set_buffer_uptodate(bh);
|
||||
unlock_buffer(bh);
|
||||
ocfs2_set_buffer_uptodate(gqinode, bh);
|
||||
err = ocfs2_journal_access_dq(handle, gqinode, bh, ja_type);
|
||||
ocfs2_set_buffer_uptodate(INODE_CACHE(gqinode), bh);
|
||||
err = ocfs2_journal_access_dq(handle, INODE_CACHE(gqinode), bh,
|
||||
ja_type);
|
||||
if (err < 0) {
|
||||
brelse(bh);
|
||||
goto out;
|
||||
|
@ -108,7 +108,7 @@ static int ocfs2_modify_bh(struct inode *inode, struct buffer_head *bh,
|
||||
mlog_errno(status);
|
||||
return status;
|
||||
}
|
||||
status = ocfs2_journal_access_dq(handle, inode, bh,
|
||||
status = ocfs2_journal_access_dq(handle, INODE_CACHE(inode), bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
@ -510,7 +510,8 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
|
||||
goto out_commit;
|
||||
}
|
||||
/* Release local quota file entry */
|
||||
status = ocfs2_journal_access_dq(handle, lqinode,
|
||||
status = ocfs2_journal_access_dq(handle,
|
||||
INODE_CACHE(lqinode),
|
||||
qbh, OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
@ -619,7 +620,8 @@ int ocfs2_finish_quota_recovery(struct ocfs2_super *osb,
|
||||
mlog_errno(status);
|
||||
goto out_bh;
|
||||
}
|
||||
status = ocfs2_journal_access_dq(handle, lqinode, bh,
|
||||
status = ocfs2_journal_access_dq(handle, INODE_CACHE(lqinode),
|
||||
bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
@ -993,8 +995,8 @@ static struct ocfs2_quota_chunk *ocfs2_local_quota_add_chunk(
|
||||
goto out_trans;
|
||||
}
|
||||
dchunk = (struct ocfs2_local_disk_chunk *)bh->b_data;
|
||||
ocfs2_set_new_buffer_uptodate(lqinode, bh);
|
||||
status = ocfs2_journal_access_dq(handle, lqinode, bh,
|
||||
ocfs2_set_new_buffer_uptodate(INODE_CACHE(lqinode), bh);
|
||||
status = ocfs2_journal_access_dq(handle, INODE_CACHE(lqinode), bh,
|
||||
OCFS2_JOURNAL_ACCESS_CREATE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
@ -1027,8 +1029,8 @@ static struct ocfs2_quota_chunk *ocfs2_local_quota_add_chunk(
|
||||
mlog_errno(status);
|
||||
goto out_trans;
|
||||
}
|
||||
ocfs2_set_new_buffer_uptodate(lqinode, dbh);
|
||||
status = ocfs2_journal_access_dq(handle, lqinode, dbh,
|
||||
ocfs2_set_new_buffer_uptodate(INODE_CACHE(lqinode), dbh);
|
||||
status = ocfs2_journal_access_dq(handle, INODE_CACHE(lqinode), dbh,
|
||||
OCFS2_JOURNAL_ACCESS_CREATE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
@ -1131,7 +1133,7 @@ static struct ocfs2_quota_chunk *ocfs2_extend_local_quota_file(
|
||||
mlog_errno(status);
|
||||
goto out;
|
||||
}
|
||||
ocfs2_set_new_buffer_uptodate(lqinode, bh);
|
||||
ocfs2_set_new_buffer_uptodate(INODE_CACHE(lqinode), bh);
|
||||
|
||||
/* Local quota info, chunk header and the new block we initialize */
|
||||
handle = ocfs2_start_trans(OCFS2_SB(sb),
|
||||
@ -1143,7 +1145,7 @@ static struct ocfs2_quota_chunk *ocfs2_extend_local_quota_file(
|
||||
goto out;
|
||||
}
|
||||
/* Zero created block */
|
||||
status = ocfs2_journal_access_dq(handle, lqinode, bh,
|
||||
status = ocfs2_journal_access_dq(handle, INODE_CACHE(lqinode), bh,
|
||||
OCFS2_JOURNAL_ACCESS_CREATE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
@ -1158,7 +1160,8 @@ static struct ocfs2_quota_chunk *ocfs2_extend_local_quota_file(
|
||||
goto out_trans;
|
||||
}
|
||||
/* Update chunk header */
|
||||
status = ocfs2_journal_access_dq(handle, lqinode, chunk->qc_headerbh,
|
||||
status = ocfs2_journal_access_dq(handle, INODE_CACHE(lqinode),
|
||||
chunk->qc_headerbh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
@ -1292,7 +1295,8 @@ static int ocfs2_local_release_dquot(struct dquot *dquot)
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = ocfs2_journal_access_dq(handle, sb_dqopt(sb)->files[type],
|
||||
status = ocfs2_journal_access_dq(handle,
|
||||
INODE_CACHE(sb_dqopt(sb)->files[type]),
|
||||
od->dq_chunk->qc_headerbh, OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
|
4313
fs/ocfs2/refcounttree.c
Normal file
4313
fs/ocfs2/refcounttree.c
Normal file
File diff suppressed because it is too large
Load Diff
106
fs/ocfs2/refcounttree.h
Normal file
106
fs/ocfs2/refcounttree.h
Normal file
@ -0,0 +1,106 @@
|
||||
/* -*- mode: c; c-basic-offset: 8; -*-
|
||||
* vim: noexpandtab sw=8 ts=8 sts=0:
|
||||
*
|
||||
* refcounttree.h
|
||||
*
|
||||
* Copyright (C) 2009 Oracle. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*/
|
||||
#ifndef OCFS2_REFCOUNTTREE_H
|
||||
#define OCFS2_REFCOUNTTREE_H
|
||||
|
||||
struct ocfs2_refcount_tree {
|
||||
struct rb_node rf_node;
|
||||
u64 rf_blkno;
|
||||
u32 rf_generation;
|
||||
struct rw_semaphore rf_sem;
|
||||
struct ocfs2_lock_res rf_lockres;
|
||||
struct kref rf_getcnt;
|
||||
int rf_removed;
|
||||
|
||||
/* the following 4 fields are used by caching_info. */
|
||||
struct ocfs2_caching_info rf_ci;
|
||||
spinlock_t rf_lock;
|
||||
struct mutex rf_io_mutex;
|
||||
struct super_block *rf_sb;
|
||||
};
|
||||
|
||||
void ocfs2_purge_refcount_trees(struct ocfs2_super *osb);
|
||||
int ocfs2_lock_refcount_tree(struct ocfs2_super *osb, u64 ref_blkno, int rw,
|
||||
struct ocfs2_refcount_tree **tree,
|
||||
struct buffer_head **ref_bh);
|
||||
void ocfs2_unlock_refcount_tree(struct ocfs2_super *osb,
|
||||
struct ocfs2_refcount_tree *tree,
|
||||
int rw);
|
||||
|
||||
int ocfs2_decrease_refcount(struct inode *inode,
|
||||
handle_t *handle, u32 cpos, u32 len,
|
||||
struct ocfs2_alloc_context *meta_ac,
|
||||
struct ocfs2_cached_dealloc_ctxt *dealloc,
|
||||
int delete);
|
||||
int ocfs2_prepare_refcount_change_for_del(struct inode *inode,
|
||||
struct buffer_head *di_bh,
|
||||
u64 phys_blkno,
|
||||
u32 clusters,
|
||||
int *credits,
|
||||
struct ocfs2_alloc_context **meta_ac);
|
||||
int ocfs2_refcount_cow(struct inode *inode, struct buffer_head *di_bh,
|
||||
u32 cpos, u32 write_len, u32 max_cpos);
|
||||
|
||||
typedef int (ocfs2_post_refcount_func)(struct inode *inode,
|
||||
handle_t *handle,
|
||||
void *para);
|
||||
/*
|
||||
* Some refcount caller need to do more work after we modify the data b-tree
|
||||
* during refcount operation(including CoW and add refcount flag), and make the
|
||||
* transaction complete. So it must give us this structure so that we can do it
|
||||
* within our transaction.
|
||||
*
|
||||
*/
|
||||
struct ocfs2_post_refcount {
|
||||
int credits; /* credits it need for journal. */
|
||||
ocfs2_post_refcount_func *func; /* real function. */
|
||||
void *para;
|
||||
};
|
||||
|
||||
int ocfs2_refcounted_xattr_delete_need(struct inode *inode,
|
||||
struct ocfs2_caching_info *ref_ci,
|
||||
struct buffer_head *ref_root_bh,
|
||||
struct ocfs2_xattr_value_root *xv,
|
||||
int *meta_add, int *credits);
|
||||
int ocfs2_refcount_cow_xattr(struct inode *inode,
|
||||
struct ocfs2_dinode *di,
|
||||
struct ocfs2_xattr_value_buf *vb,
|
||||
struct ocfs2_refcount_tree *ref_tree,
|
||||
struct buffer_head *ref_root_bh,
|
||||
u32 cpos, u32 write_len,
|
||||
struct ocfs2_post_refcount *post);
|
||||
int ocfs2_add_refcount_flag(struct inode *inode,
|
||||
struct ocfs2_extent_tree *data_et,
|
||||
struct ocfs2_caching_info *ref_ci,
|
||||
struct buffer_head *ref_root_bh,
|
||||
u32 cpos, u32 p_cluster, u32 num_clusters,
|
||||
struct ocfs2_cached_dealloc_ctxt *dealloc,
|
||||
struct ocfs2_post_refcount *post);
|
||||
int ocfs2_remove_refcount_tree(struct inode *inode, struct buffer_head *di_bh);
|
||||
int ocfs2_try_remove_refcount_tree(struct inode *inode,
|
||||
struct buffer_head *di_bh);
|
||||
int ocfs2_increase_refcount(handle_t *handle,
|
||||
struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *ref_root_bh,
|
||||
u64 cpos, u32 len,
|
||||
struct ocfs2_alloc_context *meta_ac,
|
||||
struct ocfs2_cached_dealloc_ctxt *dealloc);
|
||||
int ocfs2_reflink_ioctl(struct inode *inode,
|
||||
const char __user *oldname,
|
||||
const char __user *newname,
|
||||
bool preserve);
|
||||
#endif /* OCFS2_REFCOUNTTREE_H */
|
@ -106,8 +106,8 @@ static int ocfs2_update_last_group_and_inode(handle_t *handle,
|
||||
mlog_entry("(new_clusters=%d, first_new_cluster = %u)\n",
|
||||
new_clusters, first_new_cluster);
|
||||
|
||||
ret = ocfs2_journal_access_gd(handle, bm_inode, group_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
ret = ocfs2_journal_access_gd(handle, INODE_CACHE(bm_inode),
|
||||
group_bh, OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (ret < 0) {
|
||||
mlog_errno(ret);
|
||||
goto out;
|
||||
@ -141,7 +141,7 @@ static int ocfs2_update_last_group_and_inode(handle_t *handle,
|
||||
}
|
||||
|
||||
/* update the inode accordingly. */
|
||||
ret = ocfs2_journal_access_di(handle, bm_inode, bm_bh,
|
||||
ret = ocfs2_journal_access_di(handle, INODE_CACHE(bm_inode), bm_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (ret < 0) {
|
||||
mlog_errno(ret);
|
||||
@ -514,7 +514,7 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
ocfs2_set_new_buffer_uptodate(inode, group_bh);
|
||||
ocfs2_set_new_buffer_uptodate(INODE_CACHE(inode), group_bh);
|
||||
|
||||
ret = ocfs2_verify_group_and_input(main_bm_inode, fe, input, group_bh);
|
||||
if (ret) {
|
||||
@ -536,8 +536,8 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input)
|
||||
cl = &fe->id2.i_chain;
|
||||
cr = &cl->cl_recs[input->chain];
|
||||
|
||||
ret = ocfs2_journal_access_gd(handle, main_bm_inode, group_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
ret = ocfs2_journal_access_gd(handle, INODE_CACHE(main_bm_inode),
|
||||
group_bh, OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (ret < 0) {
|
||||
mlog_errno(ret);
|
||||
goto out_commit;
|
||||
@ -552,8 +552,8 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input)
|
||||
goto out_commit;
|
||||
}
|
||||
|
||||
ret = ocfs2_journal_access_di(handle, main_bm_inode, main_bm_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
ret = ocfs2_journal_access_di(handle, INODE_CACHE(main_bm_inode),
|
||||
main_bm_bh, OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (ret < 0) {
|
||||
mlog_errno(ret);
|
||||
goto out_commit;
|
||||
|
@ -150,8 +150,8 @@ int ocfs2_refresh_slot_info(struct ocfs2_super *osb)
|
||||
* be !NULL. Thus, ocfs2_read_blocks() will ignore blocknr. If
|
||||
* this is not true, the read of -1 (UINT64_MAX) will fail.
|
||||
*/
|
||||
ret = ocfs2_read_blocks(si->si_inode, -1, si->si_blocks, si->si_bh,
|
||||
OCFS2_BH_IGNORE_CACHE, NULL);
|
||||
ret = ocfs2_read_blocks(INODE_CACHE(si->si_inode), -1, si->si_blocks,
|
||||
si->si_bh, OCFS2_BH_IGNORE_CACHE, NULL);
|
||||
if (ret == 0) {
|
||||
spin_lock(&osb->osb_lock);
|
||||
ocfs2_update_slot_info(si);
|
||||
@ -213,7 +213,7 @@ static int ocfs2_update_disk_slot(struct ocfs2_super *osb,
|
||||
ocfs2_update_disk_slot_old(si, slot_num, &bh);
|
||||
spin_unlock(&osb->osb_lock);
|
||||
|
||||
status = ocfs2_write_block(osb, bh, si->si_inode);
|
||||
status = ocfs2_write_block(osb, bh, INODE_CACHE(si->si_inode));
|
||||
if (status < 0)
|
||||
mlog_errno(status);
|
||||
|
||||
@ -404,8 +404,8 @@ static int ocfs2_map_slot_buffers(struct ocfs2_super *osb,
|
||||
(unsigned long long)blkno);
|
||||
|
||||
bh = NULL; /* Acquire a fresh bh */
|
||||
status = ocfs2_read_blocks(si->si_inode, blkno, 1, &bh,
|
||||
OCFS2_BH_IGNORE_CACHE, NULL);
|
||||
status = ocfs2_read_blocks(INODE_CACHE(si->si_inode), blkno,
|
||||
1, &bh, OCFS2_BH_IGNORE_CACHE, NULL);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
goto bail;
|
||||
|
@ -310,7 +310,7 @@ int ocfs2_read_group_descriptor(struct inode *inode, struct ocfs2_dinode *di,
|
||||
int rc;
|
||||
struct buffer_head *tmp = *bh;
|
||||
|
||||
rc = ocfs2_read_block(inode, gd_blkno, &tmp,
|
||||
rc = ocfs2_read_block(INODE_CACHE(inode), gd_blkno, &tmp,
|
||||
ocfs2_validate_group_descriptor);
|
||||
if (rc)
|
||||
goto out;
|
||||
@ -352,7 +352,7 @@ static int ocfs2_block_group_fill(handle_t *handle,
|
||||
}
|
||||
|
||||
status = ocfs2_journal_access_gd(handle,
|
||||
alloc_inode,
|
||||
INODE_CACHE(alloc_inode),
|
||||
bg_bh,
|
||||
OCFS2_JOURNAL_ACCESS_CREATE);
|
||||
if (status < 0) {
|
||||
@ -476,7 +476,7 @@ static int ocfs2_block_group_alloc(struct ocfs2_super *osb,
|
||||
mlog_errno(status);
|
||||
goto bail;
|
||||
}
|
||||
ocfs2_set_new_buffer_uptodate(alloc_inode, bg_bh);
|
||||
ocfs2_set_new_buffer_uptodate(INODE_CACHE(alloc_inode), bg_bh);
|
||||
|
||||
status = ocfs2_block_group_fill(handle,
|
||||
alloc_inode,
|
||||
@ -491,7 +491,7 @@ static int ocfs2_block_group_alloc(struct ocfs2_super *osb,
|
||||
|
||||
bg = (struct ocfs2_group_desc *) bg_bh->b_data;
|
||||
|
||||
status = ocfs2_journal_access_di(handle, alloc_inode,
|
||||
status = ocfs2_journal_access_di(handle, INODE_CACHE(alloc_inode),
|
||||
bh, OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
@ -1033,7 +1033,7 @@ static inline int ocfs2_block_group_set_bits(handle_t *handle,
|
||||
journal_type = OCFS2_JOURNAL_ACCESS_UNDO;
|
||||
|
||||
status = ocfs2_journal_access_gd(handle,
|
||||
alloc_inode,
|
||||
INODE_CACHE(alloc_inode),
|
||||
group_bh,
|
||||
journal_type);
|
||||
if (status < 0) {
|
||||
@ -1106,7 +1106,8 @@ static int ocfs2_relink_block_group(handle_t *handle,
|
||||
bg_ptr = le64_to_cpu(bg->bg_next_group);
|
||||
prev_bg_ptr = le64_to_cpu(prev_bg->bg_next_group);
|
||||
|
||||
status = ocfs2_journal_access_gd(handle, alloc_inode, prev_bg_bh,
|
||||
status = ocfs2_journal_access_gd(handle, INODE_CACHE(alloc_inode),
|
||||
prev_bg_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
@ -1121,8 +1122,8 @@ static int ocfs2_relink_block_group(handle_t *handle,
|
||||
goto out_rollback;
|
||||
}
|
||||
|
||||
status = ocfs2_journal_access_gd(handle, alloc_inode, bg_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
status = ocfs2_journal_access_gd(handle, INODE_CACHE(alloc_inode),
|
||||
bg_bh, OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
goto out_rollback;
|
||||
@ -1136,8 +1137,8 @@ static int ocfs2_relink_block_group(handle_t *handle,
|
||||
goto out_rollback;
|
||||
}
|
||||
|
||||
status = ocfs2_journal_access_di(handle, alloc_inode, fe_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
status = ocfs2_journal_access_di(handle, INODE_CACHE(alloc_inode),
|
||||
fe_bh, OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
goto out_rollback;
|
||||
@ -1288,7 +1289,7 @@ static int ocfs2_alloc_dinode_update_counts(struct inode *inode,
|
||||
struct ocfs2_dinode *di = (struct ocfs2_dinode *) di_bh->b_data;
|
||||
struct ocfs2_chain_list *cl = (struct ocfs2_chain_list *) &di->id2.i_chain;
|
||||
|
||||
ret = ocfs2_journal_access_di(handle, inode, di_bh,
|
||||
ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (ret < 0) {
|
||||
mlog_errno(ret);
|
||||
@ -1461,7 +1462,7 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac,
|
||||
/* Ok, claim our bits now: set the info on dinode, chainlist
|
||||
* and then the group */
|
||||
status = ocfs2_journal_access_di(handle,
|
||||
alloc_inode,
|
||||
INODE_CACHE(alloc_inode),
|
||||
ac->ac_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (status < 0) {
|
||||
@ -1907,8 +1908,8 @@ static inline int ocfs2_block_group_clear_bits(handle_t *handle,
|
||||
if (ocfs2_is_cluster_bitmap(alloc_inode))
|
||||
journal_type = OCFS2_JOURNAL_ACCESS_UNDO;
|
||||
|
||||
status = ocfs2_journal_access_gd(handle, alloc_inode, group_bh,
|
||||
journal_type);
|
||||
status = ocfs2_journal_access_gd(handle, INODE_CACHE(alloc_inode),
|
||||
group_bh, journal_type);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
goto bail;
|
||||
@ -1993,8 +1994,8 @@ int ocfs2_free_suballoc_bits(handle_t *handle,
|
||||
goto bail;
|
||||
}
|
||||
|
||||
status = ocfs2_journal_access_di(handle, alloc_inode, alloc_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
status = ocfs2_journal_access_di(handle, INODE_CACHE(alloc_inode),
|
||||
alloc_bh, OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
goto bail;
|
||||
@ -2151,7 +2152,7 @@ int ocfs2_lock_allocators(struct inode *inode,
|
||||
|
||||
BUG_ON(clusters_to_add != 0 && data_ac == NULL);
|
||||
|
||||
num_free_extents = ocfs2_num_free_extents(osb, inode, et);
|
||||
num_free_extents = ocfs2_num_free_extents(osb, et);
|
||||
if (num_free_extents < 0) {
|
||||
ret = num_free_extents;
|
||||
mlog_errno(ret);
|
||||
|
@ -69,6 +69,7 @@
|
||||
#include "ver.h"
|
||||
#include "xattr.h"
|
||||
#include "quota.h"
|
||||
#include "refcounttree.h"
|
||||
|
||||
#include "buffer_head_io.h"
|
||||
|
||||
@ -1668,8 +1669,6 @@ static void ocfs2_inode_init_once(void *data)
|
||||
spin_lock_init(&oi->ip_lock);
|
||||
ocfs2_extent_map_init(&oi->vfs_inode);
|
||||
INIT_LIST_HEAD(&oi->ip_io_markers);
|
||||
oi->ip_created_trans = 0;
|
||||
oi->ip_last_trans = 0;
|
||||
oi->ip_dir_start_lookup = 0;
|
||||
|
||||
init_rwsem(&oi->ip_alloc_sem);
|
||||
@ -1683,7 +1682,8 @@ static void ocfs2_inode_init_once(void *data)
|
||||
ocfs2_lock_res_init_once(&oi->ip_inode_lockres);
|
||||
ocfs2_lock_res_init_once(&oi->ip_open_lockres);
|
||||
|
||||
ocfs2_metadata_cache_init(&oi->vfs_inode);
|
||||
ocfs2_metadata_cache_init(INODE_CACHE(&oi->vfs_inode),
|
||||
&ocfs2_inode_caching_ops);
|
||||
|
||||
inode_init_once(&oi->vfs_inode);
|
||||
}
|
||||
@ -1859,6 +1859,8 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
|
||||
|
||||
ocfs2_sync_blockdev(sb);
|
||||
|
||||
ocfs2_purge_refcount_trees(osb);
|
||||
|
||||
/* No cluster connection means we've failed during mount, so skip
|
||||
* all the steps which depended on that to complete. */
|
||||
if (osb->cconn) {
|
||||
@ -2065,6 +2067,8 @@ static int ocfs2_initialize_super(struct super_block *sb,
|
||||
goto bail;
|
||||
}
|
||||
|
||||
osb->osb_rf_lock_tree = RB_ROOT;
|
||||
|
||||
osb->s_feature_compat =
|
||||
le32_to_cpu(OCFS2_RAW_SB(di)->s_feature_compat);
|
||||
osb->s_feature_ro_compat =
|
||||
@ -2490,7 +2494,8 @@ void __ocfs2_abort(struct super_block* sb,
|
||||
/* Force a panic(). This stinks, but it's better than letting
|
||||
* things continue without having a proper hard readonly
|
||||
* here. */
|
||||
OCFS2_SB(sb)->s_mount_opt |= OCFS2_MOUNT_ERRORS_PANIC;
|
||||
if (!ocfs2_mount_local(OCFS2_SB(sb)))
|
||||
OCFS2_SB(sb)->s_mount_opt |= OCFS2_MOUNT_ERRORS_PANIC;
|
||||
ocfs2_handle_error(sb);
|
||||
}
|
||||
|
||||
|
@ -75,15 +75,77 @@ struct ocfs2_meta_cache_item {
|
||||
|
||||
static struct kmem_cache *ocfs2_uptodate_cachep = NULL;
|
||||
|
||||
void ocfs2_metadata_cache_init(struct inode *inode)
|
||||
u64 ocfs2_metadata_cache_owner(struct ocfs2_caching_info *ci)
|
||||
{
|
||||
struct ocfs2_inode_info *oi = OCFS2_I(inode);
|
||||
struct ocfs2_caching_info *ci = &oi->ip_metadata_cache;
|
||||
BUG_ON(!ci || !ci->ci_ops);
|
||||
|
||||
oi->ip_flags |= OCFS2_INODE_CACHE_INLINE;
|
||||
ci->ci_num_cached = 0;
|
||||
return ci->ci_ops->co_owner(ci);
|
||||
}
|
||||
|
||||
struct super_block *ocfs2_metadata_cache_get_super(struct ocfs2_caching_info *ci)
|
||||
{
|
||||
BUG_ON(!ci || !ci->ci_ops);
|
||||
|
||||
return ci->ci_ops->co_get_super(ci);
|
||||
}
|
||||
|
||||
static void ocfs2_metadata_cache_lock(struct ocfs2_caching_info *ci)
|
||||
{
|
||||
BUG_ON(!ci || !ci->ci_ops);
|
||||
|
||||
ci->ci_ops->co_cache_lock(ci);
|
||||
}
|
||||
|
||||
static void ocfs2_metadata_cache_unlock(struct ocfs2_caching_info *ci)
|
||||
{
|
||||
BUG_ON(!ci || !ci->ci_ops);
|
||||
|
||||
ci->ci_ops->co_cache_unlock(ci);
|
||||
}
|
||||
|
||||
void ocfs2_metadata_cache_io_lock(struct ocfs2_caching_info *ci)
|
||||
{
|
||||
BUG_ON(!ci || !ci->ci_ops);
|
||||
|
||||
ci->ci_ops->co_io_lock(ci);
|
||||
}
|
||||
|
||||
void ocfs2_metadata_cache_io_unlock(struct ocfs2_caching_info *ci)
|
||||
{
|
||||
BUG_ON(!ci || !ci->ci_ops);
|
||||
|
||||
ci->ci_ops->co_io_unlock(ci);
|
||||
}
|
||||
|
||||
|
||||
static void ocfs2_metadata_cache_reset(struct ocfs2_caching_info *ci,
|
||||
int clear)
|
||||
{
|
||||
ci->ci_flags |= OCFS2_CACHE_FL_INLINE;
|
||||
ci->ci_num_cached = 0;
|
||||
|
||||
if (clear) {
|
||||
ci->ci_created_trans = 0;
|
||||
ci->ci_last_trans = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ocfs2_metadata_cache_init(struct ocfs2_caching_info *ci,
|
||||
const struct ocfs2_caching_operations *ops)
|
||||
{
|
||||
BUG_ON(!ops);
|
||||
|
||||
ci->ci_ops = ops;
|
||||
ocfs2_metadata_cache_reset(ci, 1);
|
||||
}
|
||||
|
||||
void ocfs2_metadata_cache_exit(struct ocfs2_caching_info *ci)
|
||||
{
|
||||
ocfs2_metadata_cache_purge(ci);
|
||||
ocfs2_metadata_cache_reset(ci, 1);
|
||||
}
|
||||
|
||||
|
||||
/* No lock taken here as 'root' is not expected to be visible to other
|
||||
* processes. */
|
||||
static unsigned int ocfs2_purge_copied_metadata_tree(struct rb_root *root)
|
||||
@ -112,19 +174,20 @@ static unsigned int ocfs2_purge_copied_metadata_tree(struct rb_root *root)
|
||||
* This function is a few more lines longer than necessary due to some
|
||||
* accounting done here, but I think it's worth tracking down those
|
||||
* bugs sooner -- Mark */
|
||||
void ocfs2_metadata_cache_purge(struct inode *inode)
|
||||
void ocfs2_metadata_cache_purge(struct ocfs2_caching_info *ci)
|
||||
{
|
||||
struct ocfs2_inode_info *oi = OCFS2_I(inode);
|
||||
unsigned int tree, to_purge, purged;
|
||||
struct ocfs2_caching_info *ci = &oi->ip_metadata_cache;
|
||||
struct rb_root root = RB_ROOT;
|
||||
|
||||
spin_lock(&oi->ip_lock);
|
||||
tree = !(oi->ip_flags & OCFS2_INODE_CACHE_INLINE);
|
||||
BUG_ON(!ci || !ci->ci_ops);
|
||||
|
||||
ocfs2_metadata_cache_lock(ci);
|
||||
tree = !(ci->ci_flags & OCFS2_CACHE_FL_INLINE);
|
||||
to_purge = ci->ci_num_cached;
|
||||
|
||||
mlog(0, "Purge %u %s items from Inode %llu\n", to_purge,
|
||||
tree ? "array" : "tree", (unsigned long long)oi->ip_blkno);
|
||||
mlog(0, "Purge %u %s items from Owner %llu\n", to_purge,
|
||||
tree ? "array" : "tree",
|
||||
(unsigned long long)ocfs2_metadata_cache_owner(ci));
|
||||
|
||||
/* If we're a tree, save off the root so that we can safely
|
||||
* initialize the cache. We do the work to free tree members
|
||||
@ -132,16 +195,17 @@ void ocfs2_metadata_cache_purge(struct inode *inode)
|
||||
if (tree)
|
||||
root = ci->ci_cache.ci_tree;
|
||||
|
||||
ocfs2_metadata_cache_init(inode);
|
||||
spin_unlock(&oi->ip_lock);
|
||||
ocfs2_metadata_cache_reset(ci, 0);
|
||||
ocfs2_metadata_cache_unlock(ci);
|
||||
|
||||
purged = ocfs2_purge_copied_metadata_tree(&root);
|
||||
/* If possible, track the number wiped so that we can more
|
||||
* easily detect counting errors. Unfortunately, this is only
|
||||
* meaningful for trees. */
|
||||
if (tree && purged != to_purge)
|
||||
mlog(ML_ERROR, "Inode %llu, count = %u, purged = %u\n",
|
||||
(unsigned long long)oi->ip_blkno, to_purge, purged);
|
||||
mlog(ML_ERROR, "Owner %llu, count = %u, purged = %u\n",
|
||||
(unsigned long long)ocfs2_metadata_cache_owner(ci),
|
||||
to_purge, purged);
|
||||
}
|
||||
|
||||
/* Returns the index in the cache array, -1 if not found.
|
||||
@ -182,27 +246,25 @@ ocfs2_search_cache_tree(struct ocfs2_caching_info *ci,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ocfs2_buffer_cached(struct ocfs2_inode_info *oi,
|
||||
static int ocfs2_buffer_cached(struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh)
|
||||
{
|
||||
int index = -1;
|
||||
struct ocfs2_meta_cache_item *item = NULL;
|
||||
|
||||
spin_lock(&oi->ip_lock);
|
||||
ocfs2_metadata_cache_lock(ci);
|
||||
|
||||
mlog(0, "Inode %llu, query block %llu (inline = %u)\n",
|
||||
(unsigned long long)oi->ip_blkno,
|
||||
mlog(0, "Owner %llu, query block %llu (inline = %u)\n",
|
||||
(unsigned long long)ocfs2_metadata_cache_owner(ci),
|
||||
(unsigned long long) bh->b_blocknr,
|
||||
!!(oi->ip_flags & OCFS2_INODE_CACHE_INLINE));
|
||||
!!(ci->ci_flags & OCFS2_CACHE_FL_INLINE));
|
||||
|
||||
if (oi->ip_flags & OCFS2_INODE_CACHE_INLINE)
|
||||
index = ocfs2_search_cache_array(&oi->ip_metadata_cache,
|
||||
bh->b_blocknr);
|
||||
if (ci->ci_flags & OCFS2_CACHE_FL_INLINE)
|
||||
index = ocfs2_search_cache_array(ci, bh->b_blocknr);
|
||||
else
|
||||
item = ocfs2_search_cache_tree(&oi->ip_metadata_cache,
|
||||
bh->b_blocknr);
|
||||
item = ocfs2_search_cache_tree(ci, bh->b_blocknr);
|
||||
|
||||
spin_unlock(&oi->ip_lock);
|
||||
ocfs2_metadata_cache_unlock(ci);
|
||||
|
||||
mlog(0, "index = %d, item = %p\n", index, item);
|
||||
|
||||
@ -214,7 +276,7 @@ static int ocfs2_buffer_cached(struct ocfs2_inode_info *oi,
|
||||
*
|
||||
* This can be called under lock_buffer()
|
||||
*/
|
||||
int ocfs2_buffer_uptodate(struct inode *inode,
|
||||
int ocfs2_buffer_uptodate(struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh)
|
||||
{
|
||||
/* Doesn't matter if the bh is in our cache or not -- if it's
|
||||
@ -230,24 +292,24 @@ int ocfs2_buffer_uptodate(struct inode *inode,
|
||||
|
||||
/* Ok, locally the buffer is marked as up to date, now search
|
||||
* our cache to see if we can trust that. */
|
||||
return ocfs2_buffer_cached(OCFS2_I(inode), bh);
|
||||
return ocfs2_buffer_cached(ci, bh);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* Determine whether a buffer is currently out on a read-ahead request.
|
||||
* ip_io_sem should be held to serialize submitters with the logic here.
|
||||
* ci_io_sem should be held to serialize submitters with the logic here.
|
||||
*/
|
||||
int ocfs2_buffer_read_ahead(struct inode *inode,
|
||||
int ocfs2_buffer_read_ahead(struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh)
|
||||
{
|
||||
return buffer_locked(bh) && ocfs2_buffer_cached(OCFS2_I(inode), bh);
|
||||
return buffer_locked(bh) && ocfs2_buffer_cached(ci, bh);
|
||||
}
|
||||
|
||||
/* Requires ip_lock */
|
||||
static void ocfs2_append_cache_array(struct ocfs2_caching_info *ci,
|
||||
sector_t block)
|
||||
{
|
||||
BUG_ON(ci->ci_num_cached >= OCFS2_INODE_MAX_CACHE_ARRAY);
|
||||
BUG_ON(ci->ci_num_cached >= OCFS2_CACHE_INFO_MAX_ARRAY);
|
||||
|
||||
mlog(0, "block %llu takes position %u\n", (unsigned long long) block,
|
||||
ci->ci_num_cached);
|
||||
@ -292,66 +354,64 @@ static void __ocfs2_insert_cache_tree(struct ocfs2_caching_info *ci,
|
||||
ci->ci_num_cached++;
|
||||
}
|
||||
|
||||
static inline int ocfs2_insert_can_use_array(struct ocfs2_inode_info *oi,
|
||||
struct ocfs2_caching_info *ci)
|
||||
/* co_cache_lock() must be held */
|
||||
static inline int ocfs2_insert_can_use_array(struct ocfs2_caching_info *ci)
|
||||
{
|
||||
assert_spin_locked(&oi->ip_lock);
|
||||
|
||||
return (oi->ip_flags & OCFS2_INODE_CACHE_INLINE) &&
|
||||
(ci->ci_num_cached < OCFS2_INODE_MAX_CACHE_ARRAY);
|
||||
return (ci->ci_flags & OCFS2_CACHE_FL_INLINE) &&
|
||||
(ci->ci_num_cached < OCFS2_CACHE_INFO_MAX_ARRAY);
|
||||
}
|
||||
|
||||
/* tree should be exactly OCFS2_INODE_MAX_CACHE_ARRAY wide. NULL the
|
||||
/* tree should be exactly OCFS2_CACHE_INFO_MAX_ARRAY wide. NULL the
|
||||
* pointers in tree after we use them - this allows caller to detect
|
||||
* when to free in case of error. */
|
||||
static void ocfs2_expand_cache(struct ocfs2_inode_info *oi,
|
||||
* when to free in case of error.
|
||||
*
|
||||
* The co_cache_lock() must be held. */
|
||||
static void ocfs2_expand_cache(struct ocfs2_caching_info *ci,
|
||||
struct ocfs2_meta_cache_item **tree)
|
||||
{
|
||||
int i;
|
||||
struct ocfs2_caching_info *ci = &oi->ip_metadata_cache;
|
||||
|
||||
mlog_bug_on_msg(ci->ci_num_cached != OCFS2_INODE_MAX_CACHE_ARRAY,
|
||||
"Inode %llu, num cached = %u, should be %u\n",
|
||||
(unsigned long long)oi->ip_blkno, ci->ci_num_cached,
|
||||
OCFS2_INODE_MAX_CACHE_ARRAY);
|
||||
mlog_bug_on_msg(!(oi->ip_flags & OCFS2_INODE_CACHE_INLINE),
|
||||
"Inode %llu not marked as inline anymore!\n",
|
||||
(unsigned long long)oi->ip_blkno);
|
||||
assert_spin_locked(&oi->ip_lock);
|
||||
mlog_bug_on_msg(ci->ci_num_cached != OCFS2_CACHE_INFO_MAX_ARRAY,
|
||||
"Owner %llu, num cached = %u, should be %u\n",
|
||||
(unsigned long long)ocfs2_metadata_cache_owner(ci),
|
||||
ci->ci_num_cached, OCFS2_CACHE_INFO_MAX_ARRAY);
|
||||
mlog_bug_on_msg(!(ci->ci_flags & OCFS2_CACHE_FL_INLINE),
|
||||
"Owner %llu not marked as inline anymore!\n",
|
||||
(unsigned long long)ocfs2_metadata_cache_owner(ci));
|
||||
|
||||
/* Be careful to initialize the tree members *first* because
|
||||
* once the ci_tree is used, the array is junk... */
|
||||
for(i = 0; i < OCFS2_INODE_MAX_CACHE_ARRAY; i++)
|
||||
for (i = 0; i < OCFS2_CACHE_INFO_MAX_ARRAY; i++)
|
||||
tree[i]->c_block = ci->ci_cache.ci_array[i];
|
||||
|
||||
oi->ip_flags &= ~OCFS2_INODE_CACHE_INLINE;
|
||||
ci->ci_flags &= ~OCFS2_CACHE_FL_INLINE;
|
||||
ci->ci_cache.ci_tree = RB_ROOT;
|
||||
/* this will be set again by __ocfs2_insert_cache_tree */
|
||||
ci->ci_num_cached = 0;
|
||||
|
||||
for(i = 0; i < OCFS2_INODE_MAX_CACHE_ARRAY; i++) {
|
||||
for (i = 0; i < OCFS2_CACHE_INFO_MAX_ARRAY; i++) {
|
||||
__ocfs2_insert_cache_tree(ci, tree[i]);
|
||||
tree[i] = NULL;
|
||||
}
|
||||
|
||||
mlog(0, "Expanded %llu to a tree cache: flags 0x%x, num = %u\n",
|
||||
(unsigned long long)oi->ip_blkno, oi->ip_flags, ci->ci_num_cached);
|
||||
(unsigned long long)ocfs2_metadata_cache_owner(ci),
|
||||
ci->ci_flags, ci->ci_num_cached);
|
||||
}
|
||||
|
||||
/* Slow path function - memory allocation is necessary. See the
|
||||
* comment above ocfs2_set_buffer_uptodate for more information. */
|
||||
static void __ocfs2_set_buffer_uptodate(struct ocfs2_inode_info *oi,
|
||||
static void __ocfs2_set_buffer_uptodate(struct ocfs2_caching_info *ci,
|
||||
sector_t block,
|
||||
int expand_tree)
|
||||
{
|
||||
int i;
|
||||
struct ocfs2_caching_info *ci = &oi->ip_metadata_cache;
|
||||
struct ocfs2_meta_cache_item *new = NULL;
|
||||
struct ocfs2_meta_cache_item *tree[OCFS2_INODE_MAX_CACHE_ARRAY] =
|
||||
struct ocfs2_meta_cache_item *tree[OCFS2_CACHE_INFO_MAX_ARRAY] =
|
||||
{ NULL, };
|
||||
|
||||
mlog(0, "Inode %llu, block %llu, expand = %d\n",
|
||||
(unsigned long long)oi->ip_blkno,
|
||||
mlog(0, "Owner %llu, block %llu, expand = %d\n",
|
||||
(unsigned long long)ocfs2_metadata_cache_owner(ci),
|
||||
(unsigned long long)block, expand_tree);
|
||||
|
||||
new = kmem_cache_alloc(ocfs2_uptodate_cachep, GFP_NOFS);
|
||||
@ -364,7 +424,7 @@ static void __ocfs2_set_buffer_uptodate(struct ocfs2_inode_info *oi,
|
||||
if (expand_tree) {
|
||||
/* Do *not* allocate an array here - the removal code
|
||||
* has no way of tracking that. */
|
||||
for(i = 0; i < OCFS2_INODE_MAX_CACHE_ARRAY; i++) {
|
||||
for (i = 0; i < OCFS2_CACHE_INFO_MAX_ARRAY; i++) {
|
||||
tree[i] = kmem_cache_alloc(ocfs2_uptodate_cachep,
|
||||
GFP_NOFS);
|
||||
if (!tree[i]) {
|
||||
@ -376,21 +436,21 @@ static void __ocfs2_set_buffer_uptodate(struct ocfs2_inode_info *oi,
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock(&oi->ip_lock);
|
||||
if (ocfs2_insert_can_use_array(oi, ci)) {
|
||||
ocfs2_metadata_cache_lock(ci);
|
||||
if (ocfs2_insert_can_use_array(ci)) {
|
||||
mlog(0, "Someone cleared the tree underneath us\n");
|
||||
/* Ok, items were removed from the cache in between
|
||||
* locks. Detect this and revert back to the fast path */
|
||||
ocfs2_append_cache_array(ci, block);
|
||||
spin_unlock(&oi->ip_lock);
|
||||
ocfs2_metadata_cache_unlock(ci);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (expand_tree)
|
||||
ocfs2_expand_cache(oi, tree);
|
||||
ocfs2_expand_cache(ci, tree);
|
||||
|
||||
__ocfs2_insert_cache_tree(ci, new);
|
||||
spin_unlock(&oi->ip_lock);
|
||||
ocfs2_metadata_cache_unlock(ci);
|
||||
|
||||
new = NULL;
|
||||
out_free:
|
||||
@ -400,14 +460,14 @@ out_free:
|
||||
/* If these were used, then ocfs2_expand_cache re-set them to
|
||||
* NULL for us. */
|
||||
if (tree[0]) {
|
||||
for(i = 0; i < OCFS2_INODE_MAX_CACHE_ARRAY; i++)
|
||||
for (i = 0; i < OCFS2_CACHE_INFO_MAX_ARRAY; i++)
|
||||
if (tree[i])
|
||||
kmem_cache_free(ocfs2_uptodate_cachep,
|
||||
tree[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Item insertion is guarded by ip_io_mutex, so the insertion path takes
|
||||
/* Item insertion is guarded by co_io_lock(), so the insertion path takes
|
||||
* advantage of this by not rechecking for a duplicate insert during
|
||||
* the slow case. Additionally, if the cache needs to be bumped up to
|
||||
* a tree, the code will not recheck after acquiring the lock --
|
||||
@ -425,59 +485,55 @@ out_free:
|
||||
* Readahead buffers can be passed in here before the I/O request is
|
||||
* completed.
|
||||
*/
|
||||
void ocfs2_set_buffer_uptodate(struct inode *inode,
|
||||
void ocfs2_set_buffer_uptodate(struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh)
|
||||
{
|
||||
int expand;
|
||||
struct ocfs2_inode_info *oi = OCFS2_I(inode);
|
||||
struct ocfs2_caching_info *ci = &oi->ip_metadata_cache;
|
||||
|
||||
/* The block may very well exist in our cache already, so avoid
|
||||
* doing any more work in that case. */
|
||||
if (ocfs2_buffer_cached(oi, bh))
|
||||
if (ocfs2_buffer_cached(ci, bh))
|
||||
return;
|
||||
|
||||
mlog(0, "Inode %llu, inserting block %llu\n",
|
||||
(unsigned long long)oi->ip_blkno,
|
||||
mlog(0, "Owner %llu, inserting block %llu\n",
|
||||
(unsigned long long)ocfs2_metadata_cache_owner(ci),
|
||||
(unsigned long long)bh->b_blocknr);
|
||||
|
||||
/* No need to recheck under spinlock - insertion is guarded by
|
||||
* ip_io_mutex */
|
||||
spin_lock(&oi->ip_lock);
|
||||
if (ocfs2_insert_can_use_array(oi, ci)) {
|
||||
* co_io_lock() */
|
||||
ocfs2_metadata_cache_lock(ci);
|
||||
if (ocfs2_insert_can_use_array(ci)) {
|
||||
/* Fast case - it's an array and there's a free
|
||||
* spot. */
|
||||
ocfs2_append_cache_array(ci, bh->b_blocknr);
|
||||
spin_unlock(&oi->ip_lock);
|
||||
ocfs2_metadata_cache_unlock(ci);
|
||||
return;
|
||||
}
|
||||
|
||||
expand = 0;
|
||||
if (oi->ip_flags & OCFS2_INODE_CACHE_INLINE) {
|
||||
if (ci->ci_flags & OCFS2_CACHE_FL_INLINE) {
|
||||
/* We need to bump things up to a tree. */
|
||||
expand = 1;
|
||||
}
|
||||
spin_unlock(&oi->ip_lock);
|
||||
ocfs2_metadata_cache_unlock(ci);
|
||||
|
||||
__ocfs2_set_buffer_uptodate(oi, bh->b_blocknr, expand);
|
||||
__ocfs2_set_buffer_uptodate(ci, bh->b_blocknr, expand);
|
||||
}
|
||||
|
||||
/* Called against a newly allocated buffer. Most likely nobody should
|
||||
* be able to read this sort of metadata while it's still being
|
||||
* allocated, but this is careful to take ip_io_mutex anyway. */
|
||||
void ocfs2_set_new_buffer_uptodate(struct inode *inode,
|
||||
* allocated, but this is careful to take co_io_lock() anyway. */
|
||||
void ocfs2_set_new_buffer_uptodate(struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh)
|
||||
{
|
||||
struct ocfs2_inode_info *oi = OCFS2_I(inode);
|
||||
|
||||
/* This should definitely *not* exist in our cache */
|
||||
BUG_ON(ocfs2_buffer_cached(oi, bh));
|
||||
BUG_ON(ocfs2_buffer_cached(ci, bh));
|
||||
|
||||
set_buffer_uptodate(bh);
|
||||
|
||||
mutex_lock(&oi->ip_io_mutex);
|
||||
ocfs2_set_buffer_uptodate(inode, bh);
|
||||
mutex_unlock(&oi->ip_io_mutex);
|
||||
ocfs2_metadata_cache_io_lock(ci);
|
||||
ocfs2_set_buffer_uptodate(ci, bh);
|
||||
ocfs2_metadata_cache_io_unlock(ci);
|
||||
}
|
||||
|
||||
/* Requires ip_lock. */
|
||||
@ -487,7 +543,7 @@ static void ocfs2_remove_metadata_array(struct ocfs2_caching_info *ci,
|
||||
sector_t *array = ci->ci_cache.ci_array;
|
||||
int bytes;
|
||||
|
||||
BUG_ON(index < 0 || index >= OCFS2_INODE_MAX_CACHE_ARRAY);
|
||||
BUG_ON(index < 0 || index >= OCFS2_CACHE_INFO_MAX_ARRAY);
|
||||
BUG_ON(index >= ci->ci_num_cached);
|
||||
BUG_ON(!ci->ci_num_cached);
|
||||
|
||||
@ -515,21 +571,19 @@ static void ocfs2_remove_metadata_tree(struct ocfs2_caching_info *ci,
|
||||
ci->ci_num_cached--;
|
||||
}
|
||||
|
||||
static void ocfs2_remove_block_from_cache(struct inode *inode,
|
||||
static void ocfs2_remove_block_from_cache(struct ocfs2_caching_info *ci,
|
||||
sector_t block)
|
||||
{
|
||||
int index;
|
||||
struct ocfs2_meta_cache_item *item = NULL;
|
||||
struct ocfs2_inode_info *oi = OCFS2_I(inode);
|
||||
struct ocfs2_caching_info *ci = &oi->ip_metadata_cache;
|
||||
|
||||
spin_lock(&oi->ip_lock);
|
||||
mlog(0, "Inode %llu, remove %llu, items = %u, array = %u\n",
|
||||
(unsigned long long)oi->ip_blkno,
|
||||
ocfs2_metadata_cache_lock(ci);
|
||||
mlog(0, "Owner %llu, remove %llu, items = %u, array = %u\n",
|
||||
(unsigned long long)ocfs2_metadata_cache_owner(ci),
|
||||
(unsigned long long) block, ci->ci_num_cached,
|
||||
oi->ip_flags & OCFS2_INODE_CACHE_INLINE);
|
||||
ci->ci_flags & OCFS2_CACHE_FL_INLINE);
|
||||
|
||||
if (oi->ip_flags & OCFS2_INODE_CACHE_INLINE) {
|
||||
if (ci->ci_flags & OCFS2_CACHE_FL_INLINE) {
|
||||
index = ocfs2_search_cache_array(ci, block);
|
||||
if (index != -1)
|
||||
ocfs2_remove_metadata_array(ci, index);
|
||||
@ -538,7 +592,7 @@ static void ocfs2_remove_block_from_cache(struct inode *inode,
|
||||
if (item)
|
||||
ocfs2_remove_metadata_tree(ci, item);
|
||||
}
|
||||
spin_unlock(&oi->ip_lock);
|
||||
ocfs2_metadata_cache_unlock(ci);
|
||||
|
||||
if (item)
|
||||
kmem_cache_free(ocfs2_uptodate_cachep, item);
|
||||
@ -549,23 +603,24 @@ static void ocfs2_remove_block_from_cache(struct inode *inode,
|
||||
* bother reverting things to an inlined array in the case of a remove
|
||||
* which moves us back under the limit.
|
||||
*/
|
||||
void ocfs2_remove_from_cache(struct inode *inode,
|
||||
void ocfs2_remove_from_cache(struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh)
|
||||
{
|
||||
sector_t block = bh->b_blocknr;
|
||||
|
||||
ocfs2_remove_block_from_cache(inode, block);
|
||||
ocfs2_remove_block_from_cache(ci, block);
|
||||
}
|
||||
|
||||
/* Called when we remove xattr clusters from an inode. */
|
||||
void ocfs2_remove_xattr_clusters_from_cache(struct inode *inode,
|
||||
void ocfs2_remove_xattr_clusters_from_cache(struct ocfs2_caching_info *ci,
|
||||
sector_t block,
|
||||
u32 c_len)
|
||||
{
|
||||
unsigned int i, b_len = ocfs2_clusters_to_blocks(inode->i_sb, 1) * c_len;
|
||||
struct super_block *sb = ocfs2_metadata_cache_get_super(ci);
|
||||
unsigned int i, b_len = ocfs2_clusters_to_blocks(sb, 1) * c_len;
|
||||
|
||||
for (i = 0; i < b_len; i++, block++)
|
||||
ocfs2_remove_block_from_cache(inode, block);
|
||||
ocfs2_remove_block_from_cache(ci, block);
|
||||
}
|
||||
|
||||
int __init init_ocfs2_uptodate_cache(void)
|
||||
@ -577,7 +632,7 @@ int __init init_ocfs2_uptodate_cache(void)
|
||||
return -ENOMEM;
|
||||
|
||||
mlog(0, "%u inlined cache items per inode.\n",
|
||||
OCFS2_INODE_MAX_CACHE_ARRAY);
|
||||
OCFS2_CACHE_INFO_MAX_ARRAY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -26,24 +26,59 @@
|
||||
#ifndef OCFS2_UPTODATE_H
|
||||
#define OCFS2_UPTODATE_H
|
||||
|
||||
/*
|
||||
* The caching code relies on locking provided by the user of
|
||||
* struct ocfs2_caching_info. These operations connect that up.
|
||||
*/
|
||||
struct ocfs2_caching_operations {
|
||||
/*
|
||||
* A u64 representing the owning structure. Usually this
|
||||
* is the block number (i_blkno or whatnot). This is used so
|
||||
* that caching log messages can identify the owning structure.
|
||||
*/
|
||||
u64 (*co_owner)(struct ocfs2_caching_info *ci);
|
||||
|
||||
/* The superblock is needed during I/O. */
|
||||
struct super_block *(*co_get_super)(struct ocfs2_caching_info *ci);
|
||||
/*
|
||||
* Lock and unlock the caching data. These will not sleep, and
|
||||
* should probably be spinlocks.
|
||||
*/
|
||||
void (*co_cache_lock)(struct ocfs2_caching_info *ci);
|
||||
void (*co_cache_unlock)(struct ocfs2_caching_info *ci);
|
||||
|
||||
/*
|
||||
* Lock and unlock for disk I/O. These will sleep, and should
|
||||
* be mutexes.
|
||||
*/
|
||||
void (*co_io_lock)(struct ocfs2_caching_info *ci);
|
||||
void (*co_io_unlock)(struct ocfs2_caching_info *ci);
|
||||
};
|
||||
|
||||
int __init init_ocfs2_uptodate_cache(void);
|
||||
void exit_ocfs2_uptodate_cache(void);
|
||||
|
||||
void ocfs2_metadata_cache_init(struct inode *inode);
|
||||
void ocfs2_metadata_cache_purge(struct inode *inode);
|
||||
void ocfs2_metadata_cache_init(struct ocfs2_caching_info *ci,
|
||||
const struct ocfs2_caching_operations *ops);
|
||||
void ocfs2_metadata_cache_purge(struct ocfs2_caching_info *ci);
|
||||
void ocfs2_metadata_cache_exit(struct ocfs2_caching_info *ci);
|
||||
|
||||
int ocfs2_buffer_uptodate(struct inode *inode,
|
||||
u64 ocfs2_metadata_cache_owner(struct ocfs2_caching_info *ci);
|
||||
void ocfs2_metadata_cache_io_lock(struct ocfs2_caching_info *ci);
|
||||
void ocfs2_metadata_cache_io_unlock(struct ocfs2_caching_info *ci);
|
||||
|
||||
int ocfs2_buffer_uptodate(struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh);
|
||||
void ocfs2_set_buffer_uptodate(struct inode *inode,
|
||||
void ocfs2_set_buffer_uptodate(struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh);
|
||||
void ocfs2_set_new_buffer_uptodate(struct inode *inode,
|
||||
void ocfs2_set_new_buffer_uptodate(struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh);
|
||||
void ocfs2_remove_from_cache(struct inode *inode,
|
||||
void ocfs2_remove_from_cache(struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh);
|
||||
void ocfs2_remove_xattr_clusters_from_cache(struct inode *inode,
|
||||
void ocfs2_remove_xattr_clusters_from_cache(struct ocfs2_caching_info *ci,
|
||||
sector_t block,
|
||||
u32 c_len);
|
||||
int ocfs2_buffer_read_ahead(struct inode *inode,
|
||||
int ocfs2_buffer_read_ahead(struct ocfs2_caching_info *ci,
|
||||
struct buffer_head *bh);
|
||||
|
||||
#endif /* OCFS2_UPTODATE_H */
|
||||
|
2076
fs/ocfs2/xattr.c
2076
fs/ocfs2/xattr.c
File diff suppressed because it is too large
Load Diff
@ -55,6 +55,8 @@ int ocfs2_xattr_set_handle(handle_t *, struct inode *, struct buffer_head *,
|
||||
int, const char *, const void *, size_t, int,
|
||||
struct ocfs2_alloc_context *,
|
||||
struct ocfs2_alloc_context *);
|
||||
int ocfs2_has_inline_xattr_value_outside(struct inode *inode,
|
||||
struct ocfs2_dinode *di);
|
||||
int ocfs2_xattr_remove(struct inode *, struct buffer_head *);
|
||||
int ocfs2_init_security_get(struct inode *, struct inode *,
|
||||
struct ocfs2_security_xattr_info *);
|
||||
@ -83,5 +85,16 @@ struct ocfs2_xattr_value_buf {
|
||||
struct ocfs2_xattr_value_root *vb_xv;
|
||||
};
|
||||
|
||||
|
||||
int ocfs2_xattr_attach_refcount_tree(struct inode *inode,
|
||||
struct buffer_head *fe_bh,
|
||||
struct ocfs2_caching_info *ref_ci,
|
||||
struct buffer_head *ref_root_bh,
|
||||
struct ocfs2_cached_dealloc_ctxt *dealloc);
|
||||
int ocfs2_reflink_xattrs(struct inode *old_inode,
|
||||
struct buffer_head *old_bh,
|
||||
struct inode *new_inode,
|
||||
struct buffer_head *new_bh,
|
||||
bool preserve_security);
|
||||
int ocfs2_init_security_and_acl(struct inode *dir,
|
||||
struct inode *inode);
|
||||
#endif /* OCFS2_XATTR_H */
|
||||
|
Loading…
Reference in New Issue
Block a user