Commit b64ada6b authored by Linus Torvalds's avatar Linus Torvalds

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.
  ...
parents be90a49c b80474b4
...@@ -28,6 +28,7 @@ ocfs2-objs := \ ...@@ -28,6 +28,7 @@ ocfs2-objs := \
locks.o \ locks.o \
mmap.o \ mmap.o \
namei.o \ namei.o \
refcounttree.o \
resize.o \ resize.o \
slot_map.o \ slot_map.o \
suballoc.o \ suballoc.o \
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -45,7 +45,8 @@ ...@@ -45,7 +45,8 @@
* *
* ocfs2_extent_tree contains info for the root of the b-tree, it must have a * 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 * 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 * functions for each type of metadata, so it must have the
* root_journal_access function. * root_journal_access function.
* ocfs2_extent_tree_operations abstract the normal operations we do for * ocfs2_extent_tree_operations abstract the normal operations we do for
...@@ -56,6 +57,7 @@ struct ocfs2_extent_tree { ...@@ -56,6 +57,7 @@ struct ocfs2_extent_tree {
struct ocfs2_extent_tree_operations *et_ops; struct ocfs2_extent_tree_operations *et_ops;
struct buffer_head *et_root_bh; struct buffer_head *et_root_bh;
struct ocfs2_extent_list *et_root_el; struct ocfs2_extent_list *et_root_el;
struct ocfs2_caching_info *et_ci;
ocfs2_journal_access_func et_root_journal_access; ocfs2_journal_access_func et_root_journal_access;
void *et_object; void *et_object;
unsigned int et_max_leaf_clusters; unsigned int et_max_leaf_clusters;
...@@ -66,17 +68,20 @@ struct ocfs2_extent_tree { ...@@ -66,17 +68,20 @@ struct ocfs2_extent_tree {
* specified object buffer. * specified object buffer.
*/ */
void ocfs2_init_dinode_extent_tree(struct ocfs2_extent_tree *et, void ocfs2_init_dinode_extent_tree(struct ocfs2_extent_tree *et,
struct inode *inode, struct ocfs2_caching_info *ci,
struct buffer_head *bh); struct buffer_head *bh);
void ocfs2_init_xattr_tree_extent_tree(struct ocfs2_extent_tree *et, 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 buffer_head *bh);
struct ocfs2_xattr_value_buf; struct ocfs2_xattr_value_buf;
void ocfs2_init_xattr_value_extent_tree(struct ocfs2_extent_tree *et, 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); struct ocfs2_xattr_value_buf *vb);
void ocfs2_init_dx_root_extent_tree(struct ocfs2_extent_tree *et, 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); struct buffer_head *bh);
/* /*
...@@ -84,13 +89,11 @@ void ocfs2_init_dx_root_extent_tree(struct ocfs2_extent_tree *et, ...@@ -84,13 +89,11 @@ void ocfs2_init_dx_root_extent_tree(struct ocfs2_extent_tree *et,
* allocated. This is a cached read. The extent block will be validated * allocated. This is a cached read. The extent block will be validated
* with ocfs2_validate_extent_block(). * 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 buffer_head **bh);
struct ocfs2_alloc_context; struct ocfs2_alloc_context;
int ocfs2_insert_extent(struct ocfs2_super *osb, int ocfs2_insert_extent(handle_t *handle,
handle_t *handle,
struct inode *inode,
struct ocfs2_extent_tree *et, struct ocfs2_extent_tree *et,
u32 cpos, u32 cpos,
u64 start_blk, u64 start_blk,
...@@ -103,25 +106,36 @@ enum ocfs2_alloc_restarted { ...@@ -103,25 +106,36 @@ enum ocfs2_alloc_restarted {
RESTART_TRANS, RESTART_TRANS,
RESTART_META RESTART_META
}; };
int ocfs2_add_clusters_in_btree(struct ocfs2_super *osb, int ocfs2_add_clusters_in_btree(handle_t *handle,
struct inode *inode, struct ocfs2_extent_tree *et,
u32 *logical_offset, u32 *logical_offset,
u32 clusters_to_add, u32 clusters_to_add,
int mark_unwritten, int mark_unwritten,
struct ocfs2_extent_tree *et,
handle_t *handle,
struct ocfs2_alloc_context *data_ac, struct ocfs2_alloc_context *data_ac,
struct ocfs2_alloc_context *meta_ac, struct ocfs2_alloc_context *meta_ac,
enum ocfs2_alloc_restarted *reason_ret); enum ocfs2_alloc_restarted *reason_ret);
struct ocfs2_cached_dealloc_ctxt; 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, int ocfs2_mark_extent_written(struct inode *inode,
struct ocfs2_extent_tree *et, struct ocfs2_extent_tree *et,
handle_t *handle, u32 cpos, u32 len, u32 phys, handle_t *handle, u32 cpos, u32 len, u32 phys,
struct ocfs2_alloc_context *meta_ac, struct ocfs2_alloc_context *meta_ac,
struct ocfs2_cached_dealloc_ctxt *dealloc); struct ocfs2_cached_dealloc_ctxt *dealloc);
int ocfs2_remove_extent(struct inode *inode, int ocfs2_change_extent_flag(handle_t *handle,
struct ocfs2_extent_tree *et, struct ocfs2_extent_tree *et,
u32 cpos, u32 len, handle_t *handle, 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_alloc_context *meta_ac,
struct ocfs2_cached_dealloc_ctxt *dealloc); struct ocfs2_cached_dealloc_ctxt *dealloc);
int ocfs2_remove_btree_range(struct inode *inode, int ocfs2_remove_btree_range(struct inode *inode,
...@@ -130,7 +144,6 @@ 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); struct ocfs2_cached_dealloc_ctxt *dealloc);
int ocfs2_num_free_extents(struct ocfs2_super *osb, int ocfs2_num_free_extents(struct ocfs2_super *osb,
struct inode *inode,
struct ocfs2_extent_tree *et); struct ocfs2_extent_tree *et);
/* /*
...@@ -195,6 +208,9 @@ static inline void ocfs2_init_dealloc_ctxt(struct ocfs2_cached_dealloc_ctxt *c) ...@@ -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, int ocfs2_cache_cluster_dealloc(struct ocfs2_cached_dealloc_ctxt *ctxt,
u64 blkno, unsigned int bit); 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) static inline int ocfs2_dealloc_has_cluster(struct ocfs2_cached_dealloc_ctxt *c)
{ {
return c->c_global_allocator != NULL; return c->c_global_allocator != NULL;
...@@ -222,8 +238,9 @@ int ocfs2_commit_truncate(struct ocfs2_super *osb, ...@@ -222,8 +238,9 @@ int ocfs2_commit_truncate(struct ocfs2_super *osb,
int ocfs2_truncate_inline(struct inode *inode, struct buffer_head *di_bh, int ocfs2_truncate_inline(struct inode *inode, struct buffer_head *di_bh,
unsigned int start, unsigned int end, int trunc); unsigned int start, unsigned int end, int trunc);
int ocfs2_find_leaf(struct inode *inode, struct ocfs2_extent_list *root_el, int ocfs2_find_leaf(struct ocfs2_caching_info *ci,
u32 cpos, struct buffer_head **leaf_bh); 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); 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) ...@@ -254,4 +271,50 @@ static inline int ocfs2_is_empty_extent(struct ocfs2_extent_rec *rec)
return !rec->e_leaf_clusters; 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 */ #endif /* OCFS2_ALLOC_H */
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include "suballoc.h" #include "suballoc.h"
#include "super.h" #include "super.h"
#include "symlink.h" #include "symlink.h"
#include "refcounttree.h"
#include "buffer_head_io.h" #include "buffer_head_io.h"
...@@ -126,7 +127,7 @@ static int ocfs2_symlink_get_block(struct inode *inode, sector_t iblock, ...@@ -126,7 +127,7 @@ static int ocfs2_symlink_get_block(struct inode *inode, sector_t iblock,
return err; return err;
} }
static int ocfs2_get_block(struct inode *inode, sector_t iblock, int ocfs2_get_block(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create) struct buffer_head *bh_result, int create)
{ {
int err = 0; int err = 0;
...@@ -590,6 +591,8 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock, ...@@ -590,6 +591,8 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock,
goto bail; 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 * get_more_blocks() expects us to describe a hole by clearing
* the mapped bit on bh_result(). * the mapped bit on bh_result().
...@@ -687,6 +690,10 @@ static ssize_t ocfs2_direct_IO(int rw, ...@@ -687,6 +690,10 @@ static ssize_t ocfs2_direct_IO(int rw,
if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
return 0; 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, ret = blockdev_direct_IO_no_locking(rw, iocb, inode,
inode->i_sb->s_bdev, iov, offset, inode->i_sb->s_bdev, iov, offset,
nr_segs, nr_segs,
...@@ -1259,7 +1266,8 @@ static int ocfs2_write_cluster(struct address_space *mapping, ...@@ -1259,7 +1266,8 @@ static int ocfs2_write_cluster(struct address_space *mapping,
goto out; goto out;
} }
} else if (unwritten) { } 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, ret = ocfs2_mark_extent_written(inode, &et,
wc->w_handle, cpos, 1, phys, wc->w_handle, cpos, 1, phys,
meta_ac, &wc->w_dealloc); meta_ac, &wc->w_dealloc);
...@@ -1448,6 +1456,9 @@ static int ocfs2_populate_write_desc(struct inode *inode, ...@@ -1448,6 +1456,9 @@ static int ocfs2_populate_write_desc(struct inode *inode,
goto out; goto out;
} }
/* We should already CoW the refcountd extent. */
BUG_ON(ext_flags & OCFS2_EXT_REFCOUNTED);
/* /*
* Assume worst case - that we're writing in * Assume worst case - that we're writing in
* the middle of the extent. * the middle of the extent.
...@@ -1528,7 +1539,7 @@ static int ocfs2_write_begin_inline(struct address_space *mapping, ...@@ -1528,7 +1539,7 @@ static int ocfs2_write_begin_inline(struct address_space *mapping,
goto out; 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); OCFS2_JOURNAL_ACCESS_WRITE);
if (ret) { if (ret) {
ocfs2_commit_trans(osb, handle); ocfs2_commit_trans(osb, handle);
...@@ -1699,6 +1710,19 @@ int ocfs2_write_begin_nolock(struct address_space *mapping, ...@@ -1699,6 +1710,19 @@ int ocfs2_write_begin_nolock(struct address_space *mapping,
goto out; 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, ret = ocfs2_populate_write_desc(inode, wc, &clusters_to_alloc,
&extents_to_split); &extents_to_split);
if (ret) { if (ret) {
...@@ -1726,7 +1750,8 @@ int ocfs2_write_begin_nolock(struct address_space *mapping, ...@@ -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), (long long)i_size_read(inode), le32_to_cpu(di->i_clusters),
clusters_to_alloc, extents_to_split); 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, ret = ocfs2_lock_allocators(inode, &et,
clusters_to_alloc, extents_to_split, clusters_to_alloc, extents_to_split,
&data_ac, &meta_ac); &data_ac, &meta_ac);
...@@ -1773,7 +1798,7 @@ int ocfs2_write_begin_nolock(struct address_space *mapping, ...@@ -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 * We don't want this to fail in ocfs2_write_end(), so do it
* here. * 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); OCFS2_JOURNAL_ACCESS_WRITE);
if (ret) { if (ret) {
mlog_errno(ret); mlog_errno(ret);
......
...@@ -57,6 +57,8 @@ int ocfs2_read_inline_data(struct inode *inode, struct page *page, ...@@ -57,6 +57,8 @@ int ocfs2_read_inline_data(struct inode *inode, struct page *page,
struct buffer_head *di_bh); struct buffer_head *di_bh);
int ocfs2_size_fits_inline_data(struct buffer_head *di_bh, u64 new_size); 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 */ /* all ocfs2_dio_end_io()'s fault */
#define ocfs2_iocb_is_rw_locked(iocb) \ #define ocfs2_iocb_is_rw_locked(iocb) \
test_bit(0, (unsigned long *)&iocb->private) test_bit(0, (unsigned long *)&iocb->private)
......
...@@ -52,12 +52,12 @@ enum ocfs2_state_bits { ...@@ -52,12 +52,12 @@ enum ocfs2_state_bits {
BUFFER_FNS(NeedsValidate, needs_validate); BUFFER_FNS(NeedsValidate, needs_validate);
int ocfs2_write_block(struct ocfs2_super *osb, 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 ret = 0; int ret = 0;
mlog_entry("(bh->b_blocknr = %llu, inode=%p)\n", mlog_entry("(bh->b_blocknr = %llu, ci=%p)\n",
(unsigned long long)bh->b_blocknr, inode); (unsigned long long)bh->b_blocknr, ci);
BUG_ON(bh->b_blocknr < OCFS2_SUPER_BLOCK_BLKNO); BUG_ON(bh->b_blocknr < OCFS2_SUPER_BLOCK_BLKNO);
BUG_ON(buffer_jbd(bh)); BUG_ON(buffer_jbd(bh));
...@@ -70,7 +70,7 @@ int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh, ...@@ -70,7 +70,7 @@ int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh,
goto out; goto out;
} }
mutex_lock(&OCFS2_I(inode)->ip_io_mutex); ocfs2_metadata_cache_io_lock(ci);
lock_buffer(bh); lock_buffer(bh);
set_buffer_uptodate(bh); set_buffer_uptodate(bh);
...@@ -85,7 +85,7 @@ int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh, ...@@ -85,7 +85,7 @@ int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh,
wait_on_buffer(bh); wait_on_buffer(bh);
if (buffer_uptodate(bh)) { if (buffer_uptodate(bh)) {
ocfs2_set_buffer_uptodate(inode, bh); ocfs2_set_buffer_uptodate(ci, bh);
} else { } else {
/* We don't need to remove the clustered uptodate /* We don't need to remove the clustered uptodate
* information for this bh as it's not marked locally * 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, ...@@ -94,7 +94,7 @@ int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh,
put_bh(bh); put_bh(bh);
} }
mutex_unlock(&OCFS2_I(inode)->ip_io_mutex); ocfs2_metadata_cache_io_unlock(ci);
out: out:
mlog_exit(ret); mlog_exit(ret);
return ret; return ret;
...@@ -177,7 +177,7 @@ int ocfs2_read_blocks_sync(struct ocfs2_super *osb, u64 block, ...@@ -177,7 +177,7 @@ int ocfs2_read_blocks_sync(struct ocfs2_super *osb, u64 block,
return status; 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, struct buffer_head *bhs[], int flags,
int (*validate)(struct super_block *sb, int (*validate)(struct super_block *sb,
struct buffer_head *bh)) struct buffer_head *bh))
...@@ -185,11 +185,12 @@ int ocfs2_read_blocks(struct inode *inode, u64 block, int nr, ...@@ -185,11 +185,12 @@ int ocfs2_read_blocks(struct inode *inode, u64 block, int nr,
int status = 0; int status = 0;
int i, ignore_cache = 0; int i, ignore_cache = 0;
struct buffer_head *bh; 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", mlog_entry("(ci=%p, block=(%llu), nr=(%d), flags=%d)\n",
inode, (unsigned long long)block, nr, flags); ci, (unsigned long long)block, nr, flags);
BUG_ON(!inode); BUG_ON(!ci);
BUG_ON((flags & OCFS2_BH_READAHEAD) && BUG_ON((flags & OCFS2_BH_READAHEAD) &&
(flags & OCFS2_BH_IGNORE_CACHE)); (flags & OCFS2_BH_IGNORE_CACHE));
...@@ -212,12 +213,12 @@ int ocfs2_read_blocks(struct inode *inode, u64 block, int nr, ...@@ -212,12 +213,12 @@ int ocfs2_read_blocks(struct inode *inode, u64 block, int nr,
goto bail; goto bail;
} }
mutex_lock(&OCFS2_I(inode)->ip_io_mutex); ocfs2_metadata_cache_io_lock(ci);
for (i = 0 ; i < nr ; i++) { for (i = 0 ; i < nr ; i++) {
if (bhs[i] == NULL) { if (bhs[i] == NULL) {
bhs[i] = sb_getblk(inode->i_sb, block++); bhs[i] = sb_getblk(sb, block++);
if (bhs[i] == NULL) { if (bhs[i] == NULL) {
mutex_unlock(&OCFS2_I(inode)->ip_io_mutex); ocfs2_metadata_cache_io_unlock(ci);
status = -EIO; status = -EIO;
mlog_errno(status); mlog_errno(status);
goto bail; goto bail;
...@@ -250,11 +251,11 @@ int ocfs2_read_blocks(struct inode *inode, u64 block, int nr, ...@@ -250,11 +251,11 @@ int ocfs2_read_blocks(struct inode *inode, u64 block, int nr,
* before our is-it-in-flight check. * 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, 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)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 /* We're using ignore_cache here to say
* "go to disk" */ * "go to disk" */
ignore_cache = 1; ignore_cache = 1;
...@@ -283,7 +284,7 @@ int ocfs2_read_blocks(struct inode *inode, u64 block, int nr, ...@@ -283,7 +284,7 @@ int ocfs2_read_blocks(struct inode *inode, u64 block, int nr,
* previously submitted request than we are * previously submitted request than we are
* done here. */ * done here. */
if ((flags & OCFS2_BH_READAHEAD) if ((flags & OCFS2_BH_READAHEAD)
&& ocfs2_buffer_read_ahead(inode, bh)) && ocfs2_buffer_read_ahead(ci, bh))
continue; continue;
lock_buffer(bh); lock_buffer(bh);
...@@ -305,7 +306,7 @@ int ocfs2_read_blocks(struct inode *inode, u64 block, int nr, ...@@ -305,7 +306,7 @@ int ocfs2_read_blocks(struct inode *inode, u64 block, int nr,
* buffer lock. */ * buffer lock. */
if (!(flags & OCFS2_BH_IGNORE_CACHE) if (!(flags & OCFS2_BH_IGNORE_CACHE)
&& !(flags & OCFS2_BH_READAHEAD) && !(flags & OCFS2_BH_READAHEAD)
&& ocfs2_buffer_uptodate(inode, bh)) { && ocfs2_buffer_uptodate(ci, bh)) {
unlock_buffer(bh); unlock_buffer(bh);
continue; continue;
} }
...@@ -327,7 +328,7 @@ int ocfs2_read_blocks(struct inode *inode, u64 block, int nr, ...@@ -327,7 +328,7 @@ int ocfs2_read_blocks(struct inode *inode, u64 block, int nr,
if (!(flags & OCFS2_BH_READAHEAD)) { if (!(flags & OCFS2_BH_READAHEAD)) {
/* We know this can't have changed as we hold the /* 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. */ * journal has it. */
if (!buffer_jbd(bh)) if (!buffer_jbd(bh))
wait_on_buffer(bh); wait_on_buffer(bh);
...@@ -351,7 +352,7 @@ int ocfs2_read_blocks(struct inode *inode, u64 block, int nr, ...@@ -351,7 +352,7 @@ int ocfs2_read_blocks(struct inode *inode, u64 block, int nr,
* that better not have changed */ * that better not have changed */
BUG_ON(buffer_jbd(bh)); BUG_ON(buffer_jbd(bh));
clear_buffer_needs_validate(bh); clear_buffer_needs_validate(bh);
status = validate(inode->i_sb, bh); status = validate(sb, bh);
if (status) { if (status) {
put_bh(bh); put_bh(bh);
bhs[i] = NULL; bhs[i] = NULL;
...@@ -363,9 +364,9 @@ int ocfs2_read_blocks(struct inode *inode, u64 block, int nr, ...@@ -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 /* Always set the buffer in the cache, even if it was
* a forced read, or read-ahead which hasn't yet * a forced read, or read-ahead which hasn't yet
* completed. */ * 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", mlog(ML_BH_IO, "block=(%llu), nr=(%d), cached=%s, flags=0x%x\n",
(unsigned long long)block, nr, (unsigned long long)block, nr,
...@@ -399,7 +400,7 @@ static void ocfs2_check_super_or_backup(struct super_block *sb, ...@@ -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, * 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. * into this function.
*/ */
int ocfs2_write_super_or_backup(struct ocfs2_super *osb, int ocfs2_write_super_or_backup(struct ocfs2_super *osb,
......
...@@ -33,7 +33,7 @@ void ocfs2_end_buffer_io_sync(struct buffer_head *bh, ...@@ -33,7 +33,7 @@ void ocfs2_end_buffer_io_sync(struct buffer_head *bh,
int ocfs2_write_block(struct ocfs2_super *osb, int ocfs2_write_block(struct ocfs2_super *osb,
struct buffer_head *bh, struct buffer_head *bh,
struct inode *inode); struct ocfs2_caching_info *ci);
int ocfs2_read_blocks_sync(struct ocfs2_super *osb, u64 block, int ocfs2_read_blocks_sync(struct ocfs2_super *osb, u64 block,
unsigned int nr, struct buffer_head *bhs[]); unsigned int nr, struct buffer_head *bhs[]);
...@@ -44,7 +44,7 @@ int ocfs2_read_blocks_sync(struct ocfs2_super *osb, u64 block, ...@@ -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 * be set even for a READAHEAD call, as it marks the buffer for later
* validation. * 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, struct buffer_head *bhs[], int flags,
int (*validate)(struct super_block *sb, int (*validate)(struct super_block *sb,
struct buffer_head *bh)); struct buffer_head *bh));
...@@ -55,7 +55,7 @@ int ocfs2_write_super_or_backup(struct ocfs2_super *osb, ...@@ -55,7 +55,7 @@ int ocfs2_write_super_or_backup(struct ocfs2_super *osb,
#define OCFS2_BH_IGNORE_CACHE 1 #define OCFS2_BH_IGNORE_CACHE 1
#define OCFS2_BH_READAHEAD 8 #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, struct buffer_head **bh,
int (*validate)(struct super_block *sb, int (*validate)(struct super_block *sb,
struct buffer_head *bh)) struct buffer_head *bh))
...@@ -68,7 +68,7 @@ static inline int ocfs2_read_block(struct inode *inode, u64 off, ...@@ -68,7 +68,7 @@ static inline int ocfs2_read_block(struct inode *inode, u64 off,
goto bail; goto bail;
} }
status = ocfs2_read_blocks(inode, off, 1, bh, 0, validate); status = ocfs2_read_blocks(ci, off, 1, bh, 0, validate);
bail: bail:
return status; return status;
......
...@@ -111,6 +111,7 @@ static struct mlog_attribute mlog_attrs[MLOG_MAX_BITS] = { ...@@ -111,6 +111,7 @@ static struct mlog_attribute mlog_attrs[MLOG_MAX_BITS] = {
define_mask(EXPORT), define_mask(EXPORT),
define_mask(XATTR), define_mask(XATTR),
define_mask(QUOTA), define_mask(QUOTA),
define_mask(REFCOUNT),
define_mask(ERROR), define_mask(ERROR),
define_mask(NOTICE), define_mask(NOTICE),
define_mask(KTHREAD), define_mask(KTHREAD),
......
...@@ -113,6 +113,7 @@ ...@@ -113,6 +113,7 @@
#define ML_EXPORT 0x0000000010000000ULL /* ocfs2 export operations */ #define ML_EXPORT 0x0000000010000000ULL /* ocfs2 export operations */
#define ML_XATTR 0x0000000020000000ULL /* ocfs2 extended attributes */ #define ML_XATTR 0x0000000020000000ULL /* ocfs2 extended attributes */
#define ML_QUOTA 0x0000000040000000ULL /* ocfs2 quota operations */ #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 */ /* bits that are infrequently given and frequently matched in the high word */
#define ML_ERROR 0x0000000100000000ULL /* sent to KERN_ERR */ #define ML_ERROR 0x0000000100000000ULL /* sent to KERN_ERR */
#define ML_NOTICE 0x0000000200000000ULL /* setn to KERN_NOTICE */ #define ML_NOTICE 0x0000000200000000ULL /* setn to KERN_NOTICE */
......
This diff is collapsed.
...@@ -212,14 +212,18 @@ static int dlm_purge_lockres(struct dlm_ctxt *dlm, ...@@ -212,14 +212,18 @@ static int dlm_purge_lockres(struct dlm_ctxt *dlm,
spin_lock(&dlm->spinlock); spin_lock(&dlm->spinlock);
} }
spin_lock(&res->spinlock);
if (!list_empty(&res->purge)) { if (!list_empty(&res->purge)) {
mlog(0, "removing lockres %.*s:%p from purgelist, " mlog(0, "removing lockres %.*s:%p from purgelist, "
"master = %d\n", res->lockname.len, res->lockname.name, "master = %d\n", res->lockname.len, res->lockname.name,
res, master); res, master);
list_del_init(&res->purge); list_del_init(&res->purge);
spin_unlock(&res->spinlock);
dlm_lockres_put(res); dlm_lockres_put(res);
dlm->purge_count--; dlm->purge_count--;
} } else
spin_unlock(&res->spinlock);
__dlm_unhash_lockres(res); __dlm_unhash_lockres(res);
/* lockres is not in the hash now. drop the flag and wake up /* lockres is not in the hash now. drop the flag and wake up
......
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
#include "super.h" #include "super.h"
#include "uptodate.h" #include "uptodate.h"
#include "quota.h" #include "quota.h"
#include "refcounttree.h"
#include "buffer_head_io.h" #include "buffer_head_io.h"
...@@ -110,6 +111,11 @@ static void ocfs2_dentry_post_unlock(struct ocfs2_super *osb, ...@@ -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 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) #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. */ /* 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 = { ...@@ -278,6 +284,12 @@ static struct ocfs2_lock_res_ops ocfs2_qinfo_lops = {
.flags = LOCK_TYPE_REQUIRES_REFRESH | LOCK_TYPE_USES_LVB, .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) static inline int ocfs2_is_inode_lock(struct ocfs2_lock_res *lockres)
{ {
return lockres->l_type == OCFS2_LOCK_TYPE_META || 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 ...@@ -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; 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) static inline struct ocfs2_super *ocfs2_get_lockres_osb(struct ocfs2_lock_res *lockres)
{ {
if (lockres->l_ops->get_osb) if (lockres->l_ops->get_osb)
...@@ -693,6 +711,17 @@ void ocfs2_qinfo_lock_res_init(struct ocfs2_lock_res *lockres, ...@@ -693,6 +711,17 @@ void ocfs2_qinfo_lock_res_init(struct ocfs2_lock_res *lockres,
info); 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) void ocfs2_lock_res_free(struct ocfs2_lock_res *res)
{ {
mlog_entry_void(); mlog_entry_void();
...@@ -1548,8 +1577,10 @@ int ocfs2_rw_lock(struct inode *inode, int write) ...@@ -1548,8 +1577,10 @@ int ocfs2_rw_lock(struct inode *inode, int write)
(unsigned long long)OCFS2_I(inode)->ip_blkno, (unsigned long long)OCFS2_I(inode)->ip_blkno,
write ? "EXMODE" : "PRMODE"); write ? "EXMODE" : "PRMODE");
if (ocfs2_mount_local(osb)) if (ocfs2_mount_local(osb)) {
mlog_exit(0);
return 0; return 0;
}
lockres = &OCFS2_I(inode)->ip_rw_lockres; lockres = &OCFS2_I(inode)->ip_rw_lockres;
...@@ -2127,7 +2158,7 @@ static int ocfs2_inode_lock_update(struct inode *inode, ...@@ -2127,7 +2158,7 @@ static int ocfs2_inode_lock_update(struct inode *inode,
/* This will discard any caching information we might have had /* This will discard any caching information we might have had
* for the inode metadata. */ * for the inode metadata. */
ocfs2_metadata_cache_purge(inode); ocfs2_metadata_cache_purge(INODE_CACHE(inode));
ocfs2_extent_map_trunc(inode, 0); ocfs2_extent_map_trunc(inode, 0);
...@@ -3009,6 +3040,7 @@ static void ocfs2_unlock_ast(void *opaque, int error) ...@@ -3009,6 +3040,7 @@ static void ocfs2_unlock_ast(void *opaque, int error)
"unlock_action %d\n", error, lockres->l_name, "unlock_action %d\n", error, lockres->l_name,
lockres->l_unlock_action); lockres->l_unlock_action);
spin_unlock_irqrestore(&lockres->l_lock, flags); spin_unlock_irqrestore(&lockres->l_lock, flags);
mlog_exit_void();
return; return;
} }
...@@ -3495,11 +3527,11 @@ static int ocfs2_data_convert_worker(struct ocfs2_lock_res *lockres, ...@@ -3495,11 +3527,11 @@ static int ocfs2_data_convert_worker(struct ocfs2_lock_res *lockres,
return UNBLOCK_CONTINUE; return UNBLOCK_CONTINUE;
} }
static int ocfs2_check_meta_downconvert(struct ocfs2_lock_res *lockres, static int ocfs2_ci_checkpointed(struct ocfs2_caching_info *ci,
struct ocfs2_lock_res *lockres,
int new_level) int new_level)
{ {
struct inode *inode = ocfs2_lock_res_inode(lockres); int checkpointed = ocfs2_ci_fully_checkpointed(ci);
int checkpointed = ocfs2_inode_fully_checkpointed(inode);
BUG_ON(new_level != DLM_LOCK_NL && new_level != DLM_LOCK_PR); BUG_ON(new_level != DLM_LOCK_NL && new_level != DLM_LOCK_PR);
BUG_ON(lockres->l_level != DLM_LOCK_EX && !checkpointed); BUG_ON(lockres->l_level != DLM_LOCK_EX && !checkpointed);
...@@ -3507,10 +3539,18 @@ static int ocfs2_check_meta_downconvert(struct ocfs2_lock_res *lockres, ...@@ -3507,10 +3539,18 @@ static int ocfs2_check_meta_downconvert(struct ocfs2_lock_res *lockres,
if (checkpointed) if (checkpointed)
return 1; return 1;
ocfs2_start_checkpoint(OCFS2_SB(inode->i_sb)); ocfs2_start_checkpoint(OCFS2_SB(ocfs2_metadata_cache_get_super(ci)));
return 0; 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) static void ocfs2_set_meta_lvb(struct ocfs2_lock_res *lockres)
{ {
struct inode *inode = ocfs2_lock_res_inode(lockres); struct inode *inode = ocfs2_lock_res_inode(lockres);
...@@ -3640,6 +3680,26 @@ static int ocfs2_dentry_convert_worker(struct ocfs2_lock_res *lockres, ...@@ -3640,6 +3680,26 @@ static int ocfs2_dentry_convert_worker(struct ocfs2_lock_res *lockres,
return UNBLOCK_CONTINUE_POST; 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) static void ocfs2_set_qinfo_lvb(struct ocfs2_lock_res *lockres)
{ {
struct ocfs2_qinfo_lvb *lvb; struct ocfs2_qinfo_lvb *lvb;
...@@ -3752,6 +3812,37 @@ int ocfs2_qinfo_lock(struct ocfs2_mem_dqinfo *oinfo, int ex) ...@@ -3752,6 +3812,37 @@ int ocfs2_qinfo_lock(struct ocfs2_mem_dqinfo *oinfo, int ex)
return status; 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 * This is the filesystem locking protocol. It provides the lock handling
* hooks for the underlying DLM. It has a maximum version number. * 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, ...@@ -101,6 +101,9 @@ void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres,
struct ocfs2_mem_dqinfo; struct ocfs2_mem_dqinfo;
void ocfs2_qinfo_lock_res_init(struct ocfs2_lock_res *lockres, void ocfs2_qinfo_lock_res_init(struct ocfs2_lock_res *lockres,
struct ocfs2_mem_dqinfo *info); 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); void ocfs2_lock_res_free(struct ocfs2_lock_res *res);
int ocfs2_create_new_inode_locks(struct inode *inode); int ocfs2_create_new_inode_locks(struct inode *inode);
int ocfs2_drop_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); ...@@ -148,6 +151,9 @@ int ocfs2_file_lock(struct file *file, int ex, int trylock);
void ocfs2_file_unlock(struct file *file); void ocfs2_file_unlock(struct file *file);
int ocfs2_qinfo_lock(struct ocfs2_mem_dqinfo *oinfo, int ex); int ocfs2_qinfo_lock(struct ocfs2_mem_dqinfo *oinfo, int ex);
void ocfs2_qinfo_unlock(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); void ocfs2_mark_lockres_freeing(struct ocfs2_lock_res *lockres);
......
...@@ -293,7 +293,7 @@ static int ocfs2_last_eb_is_empty(struct inode *inode, ...@@ -293,7 +293,7 @@ static int ocfs2_last_eb_is_empty(struct inode *inode,
struct ocfs2_extent_block *eb; struct ocfs2_extent_block *eb;
struct ocfs2_extent_list *el; 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) { if (ret) {
mlog_errno(ret); mlog_errno(ret);
goto out; goto out;
...@@ -353,7 +353,7 @@ static int ocfs2_search_for_hole_index(struct ocfs2_extent_list *el, ...@@ -353,7 +353,7 @@ 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 * eb_bh is NULL. Otherwise, eb_bh should point to the extent block
* containing el. * containing el.
*/ */
static int ocfs2_figure_hole_clusters(struct inode *inode, int ocfs2_figure_hole_clusters(struct ocfs2_caching_info *ci,
struct ocfs2_extent_list *el, struct ocfs2_extent_list *el,
struct buffer_head *eb_bh, struct buffer_head *eb_bh,
u32 v_cluster, u32 v_cluster,
...@@ -375,7 +375,7 @@ static int ocfs2_figure_hole_clusters(struct inode *inode, ...@@ -375,7 +375,7 @@ static int ocfs2_figure_hole_clusters(struct inode *inode,
if (le64_to_cpu(eb->h_next_leaf_blk) == 0ULL) if (le64_to_cpu(eb->h_next_leaf_blk) == 0ULL)
goto no_more_extents; goto no_more_extents;
ret = ocfs2_read_extent_block(inode, ret = ocfs2_read_extent_block(ci,
le64_to_cpu(eb->h_next_leaf_blk), le64_to_cpu(eb->h_next_leaf_blk),
&next_eb_bh); &next_eb_bh);
if (ret) { if (ret) {
...@@ -428,7 +428,8 @@ static int ocfs2_get_clusters_nocache(struct inode *inode, ...@@ -428,7 +428,8 @@ static int ocfs2_get_clusters_nocache(struct inode *inode,
tree_height = le16_to_cpu(el->l_tree_depth); tree_height = le16_to_cpu(el->l_tree_depth);
if (tree_height > 0) { 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) { if (ret) {
mlog_errno(ret); mlog_errno(ret);
goto out; goto out;
...@@ -455,7 +456,8 @@ static int ocfs2_get_clusters_nocache(struct inode *inode, ...@@ -455,7 +456,8 @@ static int ocfs2_get_clusters_nocache(struct inode *inode,
* field. * field.
*/ */
if (hole_len) { 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); v_cluster, &len);
if (ret) { if (ret) {
mlog_errno(ret); mlog_errno(ret);
...@@ -539,7 +541,8 @@ static void ocfs2_relative_extent_offsets(struct super_block *sb, ...@@ -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, int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster,
u32 *p_cluster, u32 *num_clusters, u32 *p_cluster, u32 *num_clusters,
struct ocfs2_extent_list *el) struct ocfs2_extent_list *el,
unsigned int *extent_flags)
{ {
int ret = 0, i; int ret = 0, i;
struct buffer_head *eb_bh = NULL; struct buffer_head *eb_bh = NULL;
...@@ -548,7 +551,8 @@ int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster, ...@@ -548,7 +551,8 @@ int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster,
u32 coff; u32 coff;
if (el->l_tree_depth) { 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) { if (ret) {
mlog_errno(ret); mlog_errno(ret);
goto out; goto out;
...@@ -590,6 +594,9 @@ int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster, ...@@ -590,6 +594,9 @@ int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster,
*p_cluster = *p_cluster + coff; *p_cluster = *p_cluster + coff;
if (num_clusters) if (num_clusters)
*num_clusters = ocfs2_rec_clusters(el, rec) - coff; *num_clusters = ocfs2_rec_clusters(el, rec) - coff;
if (extent_flags)
*extent_flags = rec->e_flags;
} }
out: out:
if (eb_bh) if (eb_bh)
...@@ -862,8 +869,8 @@ int ocfs2_read_virt_blocks(struct inode *inode, u64 v_block, int nr, ...@@ -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)); BUG_ON(bhs[done + i]->b_blocknr != (p_block + i));
} }
rc = ocfs2_read_blocks(inode, p_block, count, bhs + done, rc = ocfs2_read_blocks(INODE_CACHE(inode), p_block, count,
flags, validate); bhs + done, flags, validate);
if (rc) { if (rc) {
mlog_errno(rc); mlog_errno(rc);
break; break;
......
...@@ -55,12 +55,18 @@ int ocfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, ...@@ -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, int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster,
u32 *p_cluster, u32 *num_clusters, 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, int ocfs2_read_virt_blocks(struct inode *inode, u64 v_block, int nr,
struct buffer_head *bhs[], int flags, struct buffer_head *bhs[], int flags,
int (*validate)(struct super_block *sb, int (*validate)(struct super_block *sb,
struct buffer_head *bh)); 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, static inline int ocfs2_read_virt_block(struct inode *inode, u64 v_block,
struct buffer_head **bh, struct buffer_head **bh,
int (*validate)(struct super_block *sb, int (*validate)(struct super_block *sb,
......
...@@ -59,6 +59,7 @@ ...@@ -59,6 +59,7 @@
#include "xattr.h" #include "xattr.h"
#include "acl.h" #include "acl.h"
#include "quota.h" #include "quota.h"
#include "refcounttree.h"
#include "buffer_head_io.h" #include "buffer_head_io.h"
...@@ -259,7 +260,7 @@ int ocfs2_update_inode_atime(struct inode *inode, ...@@ -259,7 +260,7 @@ int ocfs2_update_inode_atime(struct inode *inode,
goto out; goto out;
} }
ret = ocfs2_journal_access_di(handle, inode, bh, ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), bh,
OCFS2_JOURNAL_ACCESS_WRITE); OCFS2_JOURNAL_ACCESS_WRITE);
if (ret) { if (ret) {
mlog_errno(ret); mlog_errno(ret);
...@@ -334,6 +335,39 @@ int ocfs2_simple_size_update(struct inode *inode, ...@@ -334,6 +335,39 @@ int ocfs2_simple_size_update(struct inode *inode,
return ret; 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, static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb,
struct inode *inode, struct inode *inode,
struct buffer_head *fe_bh, struct buffer_head *fe_bh,
...@@ -346,6 +380,17 @@ static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb, ...@@ -346,6 +380,17 @@ static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb,
mlog_entry_void(); 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 /* TODO: This needs to actually orphan the inode in this
* transaction. */ * transaction. */
...@@ -356,7 +401,7 @@ static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb, ...@@ -356,7 +401,7 @@ static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb,
goto out; 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); OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
...@@ -486,6 +531,8 @@ static int ocfs2_truncate_file(struct inode *inode, ...@@ -486,6 +531,8 @@ static int ocfs2_truncate_file(struct inode *inode,
up_write(&OCFS2_I(inode)->ip_alloc_sem); up_write(&OCFS2_I(inode)->ip_alloc_sem);
bail: bail:
if (!status && OCFS2_I(inode)->ip_clusters == 0)
status = ocfs2_try_remove_refcount_tree(inode, di_bh);
mlog_exit(status); mlog_exit(status);
return status; return status;
...@@ -515,10 +562,9 @@ int ocfs2_add_inode_data(struct ocfs2_super *osb, ...@@ -515,10 +562,9 @@ int ocfs2_add_inode_data(struct ocfs2_super *osb,
int ret; int ret;
struct ocfs2_extent_tree et; struct ocfs2_extent_tree et;
ocfs2_init_dinode_extent_tree(&et, inode, fe_bh); ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(inode), fe_bh);
ret = ocfs2_add_clusters_in_btree(osb, inode, logical_offset, ret = ocfs2_add_clusters_in_btree(handle, &et, logical_offset,
clusters_to_add, mark_unwritten, clusters_to_add, mark_unwritten,
&et, handle,
data_ac, meta_ac, reason_ret); data_ac, meta_ac, reason_ret);
return ret; return ret;
...@@ -564,7 +610,7 @@ static int __ocfs2_extend_allocation(struct inode *inode, u32 logical_start, ...@@ -564,7 +610,7 @@ static int __ocfs2_extend_allocation(struct inode *inode, u32 logical_start,
(unsigned long long)OCFS2_I(inode)->ip_blkno, (unsigned long long)OCFS2_I(inode)->ip_blkno,
(long long)i_size_read(inode), le32_to_cpu(fe->i_clusters), (long long)i_size_read(inode), le32_to_cpu(fe->i_clusters),
clusters_to_add); 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, status = ocfs2_lock_allocators(inode, &et, clusters_to_add, 0,
&data_ac, &meta_ac); &data_ac, &meta_ac);
if (status) { if (status) {
...@@ -593,7 +639,7 @@ static int __ocfs2_extend_allocation(struct inode *inode, u32 logical_start, ...@@ -593,7 +639,7 @@ static int __ocfs2_extend_allocation(struct inode *inode, u32 logical_start,
/* reserve a write to the file entry early on - that we if we /* reserve a write to the file entry early on - that we if we
* run out of credits in the allocation path, we can still * run out of credits in the allocation path, we can still
* update i_size. */ * 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); OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
...@@ -1131,7 +1177,7 @@ static int __ocfs2_write_remove_suid(struct inode *inode, ...@@ -1131,7 +1177,7 @@ static int __ocfs2_write_remove_suid(struct inode *inode,
goto out; goto out;
} }
ret = ocfs2_journal_access_di(handle, inode, bh, ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), bh,
OCFS2_JOURNAL_ACCESS_WRITE); OCFS2_JOURNAL_ACCESS_WRITE);
if (ret < 0) { if (ret < 0) {
mlog_errno(ret); mlog_errno(ret);
...@@ -1395,7 +1441,7 @@ static int ocfs2_remove_inode_range(struct inode *inode, ...@@ -1395,7 +1441,7 @@ static int ocfs2_remove_inode_range(struct inode *inode,
struct address_space *mapping = inode->i_mapping; struct address_space *mapping = inode->i_mapping;
struct ocfs2_extent_tree et; 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); ocfs2_init_dealloc_ctxt(&dealloc);
if (byte_len == 0) if (byte_len == 0)
...@@ -1657,6 +1703,70 @@ static long ocfs2_fallocate(struct inode *inode, int mode, loff_t offset, ...@@ -1657,6 +1703,70 @@ static long ocfs2_fallocate(struct inode *inode, int mode, loff_t offset,
OCFS2_IOC_RESVSP64, &sr, change_size); 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, static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
loff_t *ppos, loff_t *ppos,
size_t count, size_t count,
...@@ -1713,6 +1823,22 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry, ...@@ -1713,6 +1823,22 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
end = saved_pos + count; 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 * Skip the O_DIRECT checks if we don't need
* them. * them.
...@@ -1759,6 +1885,7 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry, ...@@ -1759,6 +1885,7 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
*ppos = saved_pos; *ppos = saved_pos;
out_unlock: out_unlock:
if (meta_level >= 0)
ocfs2_inode_unlock(inode, meta_level); ocfs2_inode_unlock(inode, meta_level);
out: out:
......
...@@ -69,4 +69,6 @@ int ocfs2_update_inode_atime(struct inode *inode, ...@@ -69,4 +69,6 @@ int ocfs2_update_inode_atime(struct inode *inode,
int ocfs2_change_file_space(struct file *file, unsigned int cmd, int ocfs2_change_file_space(struct file *file, unsigned int cmd,
struct ocfs2_space_resv *sr); struct ocfs2_space_resv *sr);
int ocfs2_check_range_for_refcount(struct inode *inode, loff_t pos,
size_t count);
#endif /* OCFS2_FILE_H */ #endif /* OCFS2_FILE_H */
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
#include "sysfile.h" #include "sysfile.h"
#include "uptodate.h" #include "uptodate.h"
#include "xattr.h" #include "xattr.h"
#include "refcounttree.h"
#include "buffer_head_io.h" #include "buffer_head_io.h"
...@@ -562,7 +563,8 @@ static int ocfs2_truncate_for_delete(struct ocfs2_super *osb, ...@@ -562,7 +563,8 @@ static int ocfs2_truncate_for_delete(struct ocfs2_super *osb,
goto out; 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); OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
...@@ -646,7 +648,7 @@ static int ocfs2_remove_inode(struct inode *inode, ...@@ -646,7 +648,7 @@ static int ocfs2_remove_inode(struct inode *inode,
} }
/* set the inodes dtime */ /* 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); OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
...@@ -662,7 +664,7 @@ static int ocfs2_remove_inode(struct inode *inode, ...@@ -662,7 +664,7 @@ static int ocfs2_remove_inode(struct inode *inode,
goto bail_commit; goto bail_commit;
} }
ocfs2_remove_from_cache(inode, di_bh); ocfs2_remove_from_cache(INODE_CACHE(inode), di_bh);
vfs_dq_free_inode(inode); vfs_dq_free_inode(inode);
status = ocfs2_free_dinode(handle, inode_alloc_inode, status = ocfs2_free_dinode(handle, inode_alloc_inode,
...@@ -781,6 +783,12 @@ static int ocfs2_wipe_inode(struct inode *inode, ...@@ -781,6 +783,12 @@ static int ocfs2_wipe_inode(struct inode *inode,
goto bail_unlock_dir; 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, status = ocfs2_remove_inode(inode, di_bh, orphan_dir_inode,
orphan_dir_bh); orphan_dir_bh);
if (status < 0) if (status < 0)
...@@ -1112,13 +1120,14 @@ void ocfs2_clear_inode(struct inode *inode) ...@@ -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_inode_lockres);
ocfs2_lock_res_free(&oi->ip_open_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", "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", "Clear inode of %llu, inode has a bad flag\n",
(unsigned long long)oi->ip_blkno); (unsigned long long)oi->ip_blkno);
...@@ -1145,9 +1154,7 @@ void ocfs2_clear_inode(struct inode *inode) ...@@ -1145,9 +1154,7 @@ void ocfs2_clear_inode(struct inode *inode)
(unsigned long long)oi->ip_blkno, oi->ip_open_count); (unsigned long long)oi->ip_blkno, oi->ip_open_count);
/* Clear all other flags. */ /* Clear all other flags. */
oi->ip_flags = OCFS2_INODE_CACHE_INLINE; oi->ip_flags = 0;
oi->ip_created_trans = 0;
oi->ip_last_trans = 0;
oi->ip_dir_start_lookup = 0; oi->ip_dir_start_lookup = 0;
oi->ip_blkno = 0ULL; oi->ip_blkno = 0ULL;
...@@ -1239,7 +1246,7 @@ int ocfs2_mark_inode_dirty(handle_t *handle, ...@@ -1239,7 +1246,7 @@ int ocfs2_mark_inode_dirty(handle_t *handle,
mlog_entry("(inode %llu)\n", mlog_entry("(inode %llu)\n",
(unsigned long long)OCFS2_I(inode)->ip_blkno); (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); OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
...@@ -1380,8 +1387,8 @@ int ocfs2_read_inode_block_full(struct inode *inode, struct buffer_head **bh, ...@@ -1380,8 +1387,8 @@ int ocfs2_read_inode_block_full(struct inode *inode, struct buffer_head **bh,
int rc; int rc;
struct buffer_head *tmp = *bh; struct buffer_head *tmp = *bh;
rc = ocfs2_read_blocks(inode, OCFS2_I(inode)->ip_blkno, 1, &tmp, rc = ocfs2_read_blocks(INODE_CACHE(inode), OCFS2_I(inode)->ip_blkno,
flags, ocfs2_validate_inode_block); 1, &tmp, flags, ocfs2_validate_inode_block);
/* If ocfs2_read_blocks() got us a new bh, pass it up. */ /* If ocfs2_read_blocks() got us a new bh, pass it up. */
if (!rc && !*bh) if (!rc && !*bh)
...@@ -1394,3 +1401,56 @@ int ocfs2_read_inode_block(struct inode *inode, struct buffer_head **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); 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 ...@@ -60,12 +60,6 @@ struct ocfs2_inode_info
u32 ip_dir_start_lookup; 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_caching_info ip_metadata_cache;
struct ocfs2_extent_map ip_extent_map; struct ocfs2_extent_map ip_extent_map;
...@@ -106,8 +100,6 @@ struct ocfs2_inode_info ...@@ -106,8 +100,6 @@ struct ocfs2_inode_info
#define OCFS2_INODE_MAYBE_ORPHANED 0x00000020 #define OCFS2_INODE_MAYBE_ORPHANED 0x00000020
/* Does someone have the file open O_DIRECT */ /* Does someone have the file open O_DIRECT */
#define OCFS2_INODE_OPEN_DIRECT 0x00000040 #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) 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) ...@@ -120,6 +112,12 @@ static inline struct ocfs2_inode_info *OCFS2_I(struct inode *inode)
extern struct kmem_cache *ocfs2_inode_cache; extern struct kmem_cache *ocfs2_inode_cache;
extern const struct address_space_operations ocfs2_aops; 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_clear_inode(struct inode *inode);
void ocfs2_delete_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); ...@@ -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 */ /* The same, but can be passed OCFS2_BH_* flags */
int ocfs2_read_inode_block_full(struct inode *inode, struct buffer_head **bh, int ocfs2_read_inode_block_full(struct inode *inode, struct buffer_head **bh,
int flags); 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 */ #endif /* OCFS2_INODE_H */
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "ocfs2_fs.h" #include "ocfs2_fs.h"
#include "ioctl.h" #include "ioctl.h"
#include "resize.h" #include "resize.h"
#include "refcounttree.h"
#include <linux/ext2_fs.h> #include <linux/ext2_fs.h>
...@@ -115,6 +116,9 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -115,6 +116,9 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
int status; int status;
struct ocfs2_space_resv sr; struct ocfs2_space_resv sr;
struct ocfs2_new_group_input input; struct ocfs2_new_group_input input;
struct reflink_arguments args;
const char *old_path, *new_path;
bool preserve;
switch (cmd) { switch (cmd) {
case OCFS2_IOC_GETFLAGS: case OCFS2_IOC_GETFLAGS:
...@@ -160,6 +164,15 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -160,6 +164,15 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return -EFAULT; return -EFAULT;
return ocfs2_group_add(inode, &input); 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: default:
return -ENOTTY; return -ENOTTY;
} }
...@@ -182,6 +195,7 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg) ...@@ -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_EXTEND:
case OCFS2_IOC_GROUP_ADD: case OCFS2_IOC_GROUP_ADD:
case OCFS2_IOC_GROUP_ADD64: case OCFS2_IOC_GROUP_ADD64:
case OCFS2_IOC_REFLINK:
break; break;
default: default:
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
#include "slot_map.h" #include "slot_map.h"
#include "super.h" #include "super.h"
#include "sysfile.h" #include "sysfile.h"
#include "uptodate.h"
#include "quota.h" #include "quota.h"
#include "buffer_head_io.h" #include "buffer_head_io.h"
...@@ -554,6 +555,14 @@ static struct ocfs2_triggers eb_triggers = { ...@@ -554,6 +555,14 @@ static struct ocfs2_triggers eb_triggers = {
.ot_offset = offsetof(struct ocfs2_extent_block, h_check), .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 = { static struct ocfs2_triggers gd_triggers = {
.ot_triggers = { .ot_triggers = {
.t_commit = ocfs2_commit_trigger, .t_commit = ocfs2_commit_trigger,
...@@ -601,14 +610,16 @@ static struct ocfs2_triggers dl_triggers = { ...@@ -601,14 +610,16 @@ static struct ocfs2_triggers dl_triggers = {
}; };
static int __ocfs2_journal_access(handle_t *handle, static int __ocfs2_journal_access(handle_t *handle,
struct inode *inode, struct ocfs2_caching_info *ci,
struct buffer_head *bh, struct buffer_head *bh,
struct ocfs2_triggers *triggers, struct ocfs2_triggers *triggers,
int type) int type)
{ {
int status; 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(!handle);
BUG_ON(!bh); BUG_ON(!bh);
...@@ -627,15 +638,15 @@ static int __ocfs2_journal_access(handle_t *handle, ...@@ -627,15 +638,15 @@ static int __ocfs2_journal_access(handle_t *handle,
BUG(); 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 * 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 * thread updating the current transaction id until
* ocfs2_commit_trans() because ocfs2_start_trans() took * ocfs2_commit_trans() because ocfs2_start_trans() took
* j_trans_barrier for us. */ * 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) { switch (type) {
case OCFS2_JOURNAL_ACCESS_CREATE: case OCFS2_JOURNAL_ACCESS_CREATE:
case OCFS2_JOURNAL_ACCESS_WRITE: case OCFS2_JOURNAL_ACCESS_WRITE:
...@@ -650,9 +661,9 @@ static int __ocfs2_journal_access(handle_t *handle, ...@@ -650,9 +661,9 @@ static int __ocfs2_journal_access(handle_t *handle,
status = -EINVAL; status = -EINVAL;
mlog(ML_ERROR, "Uknown access type!\n"); 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); 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) if (status < 0)
mlog(ML_ERROR, "Error %d getting %d access to buffer!\n", mlog(ML_ERROR, "Error %d getting %d access to buffer!\n",
...@@ -662,66 +673,65 @@ static int __ocfs2_journal_access(handle_t *handle, ...@@ -662,66 +673,65 @@ static int __ocfs2_journal_access(handle_t *handle,
return status; return status;
} }
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) struct buffer_head *bh, int type)
{ {
return __ocfs2_journal_access(handle, inode, bh, &di_triggers, return __ocfs2_journal_access(handle, ci, bh, &di_triggers, type);
type);
} }
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) struct buffer_head *bh, int type)
{ {
return __ocfs2_journal_access(handle, inode, bh, &eb_triggers, return __ocfs2_journal_access(handle, ci, bh, &eb_triggers, type);
type);
} }
int ocfs2_journal_access_gd(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) struct buffer_head *bh, int type)
{ {
return __ocfs2_journal_access(handle, inode, bh, &gd_triggers, return __ocfs2_journal_access(handle, ci, bh, &rb_triggers,
type); type);
} }
int ocfs2_journal_access_db(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) struct buffer_head *bh, int type)
{ {
return __ocfs2_journal_access(handle, inode, bh, &db_triggers, return __ocfs2_journal_access(handle, ci, bh, &gd_triggers, type);
type);
} }
int ocfs2_journal_access_xb(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) struct buffer_head *bh, int type)
{ {
return __ocfs2_journal_access(handle, inode, bh, &xb_triggers, return __ocfs2_journal_access(handle, ci, bh, &db_triggers, type);
type);
} }
int ocfs2_journal_access_dq(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) struct buffer_head *bh, int type)
{ {
return __ocfs2_journal_access(handle, inode, bh, &dq_triggers, return __ocfs2_journal_access(handle, ci, bh, &xb_triggers, type);
type);
} }
int ocfs2_journal_access_dr(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) struct buffer_head *bh, int type)
{ {
return __ocfs2_journal_access(handle, inode, bh, &dr_triggers, return __ocfs2_journal_access(handle, ci, bh, &dq_triggers, type);
type);
} }
int ocfs2_journal_access_dl(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) struct buffer_head *bh, int type)
{ {
return __ocfs2_journal_access(handle, inode, bh, &dl_triggers, return __ocfs2_journal_access(handle, ci, bh, &dr_triggers, type);
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 inode *inode, int ocfs2_journal_access(handle_t *handle, struct ocfs2_caching_info *ci,
struct buffer_head *bh, int type) 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, int ocfs2_journal_dirty(handle_t *handle,
...@@ -898,7 +908,7 @@ static int ocfs2_journal_toggle_dirty(struct ocfs2_super *osb, ...@@ -898,7 +908,7 @@ static int ocfs2_journal_toggle_dirty(struct ocfs2_super *osb,
ocfs2_bump_recovery_generation(fe); ocfs2_bump_recovery_generation(fe);
ocfs2_compute_meta_ecc(osb->sb, bh->b_data, &fe->i_check); 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) if (status < 0)
mlog_errno(status); mlog_errno(status);
...@@ -1642,7 +1652,7 @@ static int ocfs2_replay_journal(struct ocfs2_super *osb, ...@@ -1642,7 +1652,7 @@ static int ocfs2_replay_journal(struct ocfs2_super *osb,
ocfs2_get_recovery_generation(fe); ocfs2_get_recovery_generation(fe);
ocfs2_compute_meta_ecc(osb->sb, bh->b_data, &fe->i_check); 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) if (status < 0)
mlog_errno(status); mlog_errno(status);
......
...@@ -90,56 +90,66 @@ static inline unsigned long ocfs2_inc_trans_id(struct ocfs2_journal *j) ...@@ -90,56 +90,66 @@ static inline unsigned long ocfs2_inc_trans_id(struct ocfs2_journal *j)
return old_id; return old_id;
} }
static inline void ocfs2_set_inode_lock_trans(struct ocfs2_journal *journal, static inline void ocfs2_set_ci_lock_trans(struct ocfs2_journal *journal,
struct inode *inode) struct ocfs2_caching_info *ci)
{ {
spin_lock(&trans_inc_lock); 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); spin_unlock(&trans_inc_lock);
} }
/* Used to figure out whether it's safe to drop a metadata lock on an /* 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 * checkpointed to disk. You should be holding the spinlock on the
* metadata lock while calling this to be sure that nobody can take * metadata lock while calling this to be sure that nobody can take
* the lock and put it on another transaction. */ * 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; 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); 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); spin_unlock(&trans_inc_lock);
return ret; return ret;
} }
/* convenience function to check if an inode is still new (has never /* convenience function to check if an object backed by struct
* hit disk) Will do you a favor and set created_trans = 0 when you've * ocfs2_caching_info is still new (has never hit disk) Will do you a
* been checkpointed. returns '1' if the inode is still new. */ * favor and set created_trans = 0 when you've
static inline int ocfs2_inode_is_new(struct inode *inode) * been checkpointed. returns '1' if the ci is still new. */
static inline int ocfs2_ci_is_new(struct ocfs2_caching_info *ci)
{ {
int ret; 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 /* System files are never "new" as they're written out by
* mkfs. This helps us early during mount, before we have the * mkfs. This helps us early during mount, before we have the
* journal open and j_trans_id could be junk. */ * journal open and j_trans_id could be junk. */
if (OCFS2_I(inode)->ip_flags & OCFS2_INODE_SYSTEM_FILE) if (OCFS2_I(inode)->ip_flags & OCFS2_INODE_SYSTEM_FILE)
return 0; return 0;
spin_lock(&trans_inc_lock);
ret = !(time_after(OCFS2_SB(inode->i_sb)->journal->j_trans_id, return ocfs2_ci_is_new(INODE_CACHE(inode));
OCFS2_I(inode)->ip_created_trans));
if (!ret)
OCFS2_I(inode)->ip_created_trans = 0;
spin_unlock(&trans_inc_lock);
return ret;
} }
static inline void ocfs2_inode_set_new(struct ocfs2_super *osb, static inline void ocfs2_ci_set_new(struct ocfs2_super *osb,
struct inode *inode) struct ocfs2_caching_info *ci)
{ {
spin_lock(&trans_inc_lock); 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); spin_unlock(&trans_inc_lock);
} }
...@@ -200,7 +210,7 @@ static inline void ocfs2_checkpoint_inode(struct inode *inode) ...@@ -200,7 +210,7 @@ static inline void ocfs2_checkpoint_inode(struct inode *inode)
if (ocfs2_mount_local(osb)) if (ocfs2_mount_local(osb))
return; return;
if (!ocfs2_inode_fully_checkpointed(inode)) { if (!ocfs2_ci_fully_checkpointed(INODE_CACHE(inode))) {
/* WARNING: This only kicks off a single /* WARNING: This only kicks off a single
* checkpoint. If someone races you and adds more * checkpoint. If someone races you and adds more
* metadata to the journal, you won't know, and will * metadata to the journal, you won't know, and will
...@@ -210,7 +220,7 @@ static inline void ocfs2_checkpoint_inode(struct inode *inode) ...@@ -210,7 +220,7 @@ static inline void ocfs2_checkpoint_inode(struct inode *inode)
ocfs2_start_checkpoint(osb); ocfs2_start_checkpoint(osb);
wait_event(osb->journal->j_checkpointed, 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); ...@@ -266,31 +276,34 @@ int ocfs2_extend_trans(handle_t *handle, int nblocks);
/* ocfs2_inode */ /* 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); struct buffer_head *bh, int type);
/* ocfs2_extent_block */ /* 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); struct buffer_head *bh, int type);
/* ocfs2_group_desc */ /* 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); struct buffer_head *bh, int type);
/* ocfs2_xattr_block */ /* 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); struct buffer_head *bh, int type);
/* quota blocks */ /* 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); struct buffer_head *bh, int type);
/* dirblock */ /* 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); struct buffer_head *bh, int type);
/* ocfs2_dx_root_block */ /* 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); struct buffer_head *bh, int type);
/* ocfs2_dx_leaf */ /* 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); struct buffer_head *bh, int type);
/* Anything that has no ecc */ /* 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); struct buffer_head *bh, int type);
/* /*
...@@ -477,6 +490,23 @@ static inline int ocfs2_calc_dxi_expand_credits(struct super_block *sb) ...@@ -477,6 +490,23 @@ static inline int ocfs2_calc_dxi_expand_credits(struct super_block *sb)
return credits; 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 * 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 * 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) ...@@ -297,8 +297,8 @@ void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb)
} }
memcpy(alloc_copy, alloc, bh->b_size); memcpy(alloc_copy, alloc, bh->b_size);
status = ocfs2_journal_access_di(handle, local_alloc_inode, bh, status = ocfs2_journal_access_di(handle, INODE_CACHE(local_alloc_inode),
OCFS2_JOURNAL_ACCESS_WRITE); bh, OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
goto out_commit; goto out_commit;
...@@ -392,7 +392,7 @@ int ocfs2_begin_local_alloc_recovery(struct ocfs2_super *osb, ...@@ -392,7 +392,7 @@ int ocfs2_begin_local_alloc_recovery(struct ocfs2_super *osb,
ocfs2_clear_local_alloc(alloc); ocfs2_clear_local_alloc(alloc);
ocfs2_compute_meta_ecc(osb->sb, alloc_bh->b_data, &alloc->i_check); 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) if (status < 0)
mlog_errno(status); mlog_errno(status);
...@@ -678,7 +678,8 @@ int ocfs2_claim_local_alloc_bits(struct ocfs2_super *osb, ...@@ -678,7 +678,8 @@ int ocfs2_claim_local_alloc_bits(struct ocfs2_super *osb,
* delete bits from it! */ * delete bits from it! */
*num_bits = bits_wanted; *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, osb->local_alloc_bh,
OCFS2_JOURNAL_ACCESS_WRITE); OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) { if (status < 0) {
...@@ -1156,7 +1157,8 @@ static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb, ...@@ -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); 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, osb->local_alloc_bh,
OCFS2_JOURNAL_ACCESS_WRITE); OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) { if (status < 0) {
......
This diff is collapsed.
...@@ -35,5 +35,11 @@ int ocfs2_orphan_del(struct ocfs2_super *osb, ...@@ -35,5 +35,11 @@ int ocfs2_orphan_del(struct ocfs2_super *osb,
struct inode *orphan_dir_inode, struct inode *orphan_dir_inode,
struct inode *inode, struct inode *inode,
struct buffer_head *orphan_dir_bh); 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 */ #endif /* OCFS2_NAMEI_H */
...@@ -51,20 +51,51 @@ ...@@ -51,20 +51,51 @@
/* For struct ocfs2_blockcheck_stats */ /* For struct ocfs2_blockcheck_stats */
#include "blockcheck.h" #include "blockcheck.h"
/* Caching of metadata buffers */
/* Most user visible OCFS2 inodes will have very few pieces of /* Most user visible OCFS2 inodes will have very few pieces of
* metadata, but larger files (including bitmaps, etc) must be taken * metadata, but larger files (including bitmaps, etc) must be taken
* into account when designing an access scheme. We allow a small * into account when designing an access scheme. We allow a small
* amount of inlined blocks to be stored on an array and grow the * amount of inlined blocks to be stored on an array and grow the
* structure into a rb tree when necessary. */ * 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 { 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; unsigned int ci_num_cached;
union { union {
sector_t ci_array[OCFS2_INODE_MAX_CACHE_ARRAY]; sector_t ci_array[OCFS2_CACHE_INFO_MAX_ARRAY];
struct rb_root ci_tree; struct rb_root ci_tree;
} ci_cache; } 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 /* this limits us to 256 nodes
* if we need more, we can do a kmalloc for the map */ * if we need more, we can do a kmalloc for the map */
...@@ -377,12 +408,17 @@ struct ocfs2_super ...@@ -377,12 +408,17 @@ struct ocfs2_super
/* the group we used to allocate inodes. */ /* the group we used to allocate inodes. */
u64 osb_inode_alloc_group; 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) #define OCFS2_SB(sb) ((struct ocfs2_super *)(sb)->s_fs_info)
/* Useful typedef for passing around journal access functions */ /* 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); struct buffer_head *bh, int type);
static inline int ocfs2_should_order_data(struct inode *inode) 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) ...@@ -480,6 +516,13 @@ static inline void ocfs2_add_links_count(struct ocfs2_dinode *di, int n)
ocfs2_set_links_count(di, links); 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 /* set / clear functions because cluster events can make these happen
* in parallel so we want the transitions to be atomic. this also * in parallel so we want the transitions to be atomic. this also
* means that any future flags osb_flags must be protected by spinlock * 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) ...@@ -578,6 +621,9 @@ static inline int ocfs2_uses_extended_slot_map(struct ocfs2_super *osb)
#define OCFS2_IS_VALID_DX_LEAF(ptr) \ #define OCFS2_IS_VALID_DX_LEAF(ptr) \
(!strcmp((ptr)->dl_signature, OCFS2_DX_LEAF_SIGNATURE)) (!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, static inline unsigned long ino_from_blkno(struct super_block *sb,
u64 blkno) u64 blkno)
{ {
......
...@@ -68,6 +68,7 @@ ...@@ -68,6 +68,7 @@
#define OCFS2_DIR_TRAILER_SIGNATURE "DIRTRL1" #define OCFS2_DIR_TRAILER_SIGNATURE "DIRTRL1"
#define OCFS2_DX_ROOT_SIGNATURE "DXDIR01" #define OCFS2_DX_ROOT_SIGNATURE "DXDIR01"
#define OCFS2_DX_LEAF_SIGNATURE "DXLEAF1" #define OCFS2_DX_LEAF_SIGNATURE "DXLEAF1"
#define OCFS2_REFCOUNT_BLOCK_SIGNATURE "REFCNT1"
/* Compatibility flags */ /* Compatibility flags */
#define OCFS2_HAS_COMPAT_FEATURE(sb,mask) \ #define OCFS2_HAS_COMPAT_FEATURE(sb,mask) \
...@@ -98,7 +99,8 @@ ...@@ -98,7 +99,8 @@
| OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK \ | OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK \
| OCFS2_FEATURE_INCOMPAT_XATTR \ | OCFS2_FEATURE_INCOMPAT_XATTR \
| OCFS2_FEATURE_INCOMPAT_META_ECC \ | 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 \ #define OCFS2_FEATURE_RO_COMPAT_SUPP (OCFS2_FEATURE_RO_COMPAT_UNWRITTEN \
| OCFS2_FEATURE_RO_COMPAT_USRQUOTA \ | OCFS2_FEATURE_RO_COMPAT_USRQUOTA \
| OCFS2_FEATURE_RO_COMPAT_GRPQUOTA) | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)
...@@ -160,6 +162,9 @@ ...@@ -160,6 +162,9 @@
/* Metadata checksum and error correction */ /* Metadata checksum and error correction */
#define OCFS2_FEATURE_INCOMPAT_META_ECC 0x0800 #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 * backup superblock flag is used to indicate that this volume
* has backup superblocks. * has backup superblocks.
...@@ -223,6 +228,7 @@ ...@@ -223,6 +228,7 @@
#define OCFS2_HAS_XATTR_FL (0x0002) #define OCFS2_HAS_XATTR_FL (0x0002)
#define OCFS2_INLINE_XATTR_FL (0x0004) #define OCFS2_INLINE_XATTR_FL (0x0004)
#define OCFS2_INDEXED_DIR_FL (0x0008) #define OCFS2_INDEXED_DIR_FL (0x0008)
#define OCFS2_HAS_REFCOUNT_FL (0x0010)
/* Inode attributes, keep in sync with EXT2 */ /* Inode attributes, keep in sync with EXT2 */
#define OCFS2_SECRM_FL (0x00000001) /* Secure deletion */ #define OCFS2_SECRM_FL (0x00000001) /* Secure deletion */
...@@ -243,6 +249,9 @@ ...@@ -243,6 +249,9 @@
*/ */
#define OCFS2_EXT_UNWRITTEN (0x01) /* Extent is allocated but #define OCFS2_EXT_UNWRITTEN (0x01) /* Extent is allocated but
* unwritten */ * unwritten */
#define OCFS2_EXT_REFCOUNTED (0x02) /* Extent is reference
* counted in an associated
* refcount tree */
/* /*
* ioctl commands * ioctl commands
...@@ -292,6 +301,15 @@ struct ocfs2_new_group_input { ...@@ -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_ADD _IOW('o', 2,struct ocfs2_new_group_input)
#define OCFS2_IOC_GROUP_ADD64 _IOW('o', 3,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) * Journal Flags (ocfs2_dinode.id1.journal1.i_flags)
*/ */
...@@ -717,7 +735,8 @@ struct ocfs2_dinode { ...@@ -717,7 +735,8 @@ struct ocfs2_dinode {
__le64 i_xattr_loc; __le64 i_xattr_loc;
/*80*/ struct ocfs2_block_check i_check; /* Error checking */ /*80*/ struct ocfs2_block_check i_check; /* Error checking */
/*88*/ __le64 i_dx_root; /* Pointer to dir index root block */ /*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 { /*B8*/ union {
__le64 i_pad1; /* Generic way to refer to this __le64 i_pad1; /* Generic way to refer to this
64bit union */ 64bit union */
...@@ -901,6 +920,60 @@ struct ocfs2_group_desc ...@@ -901,6 +920,60 @@ struct ocfs2_group_desc
/*40*/ __u8 bg_bitmap[0]; /*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. * On disk extended attribute structure for OCFS2.
*/ */
...@@ -1312,6 +1385,32 @@ static inline u16 ocfs2_xattr_recs_per_xb(struct super_block *sb) ...@@ -1312,6 +1385,32 @@ static inline u16 ocfs2_xattr_recs_per_xb(struct super_block *sb)
return size / sizeof(struct ocfs2_extent_rec); 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 #else
static inline int ocfs2_fast_symlink_chars(int blocksize) static inline int ocfs2_fast_symlink_chars(int blocksize)
{ {
......
...@@ -49,6 +49,7 @@ enum ocfs2_lock_type { ...@@ -49,6 +49,7 @@ enum ocfs2_lock_type {
OCFS2_LOCK_TYPE_QINFO, OCFS2_LOCK_TYPE_QINFO,
OCFS2_LOCK_TYPE_NFS_SYNC, OCFS2_LOCK_TYPE_NFS_SYNC,
OCFS2_LOCK_TYPE_ORPHAN_SCAN, OCFS2_LOCK_TYPE_ORPHAN_SCAN,
OCFS2_LOCK_TYPE_REFCOUNT,
OCFS2_NUM_LOCK_TYPES OCFS2_NUM_LOCK_TYPES
}; };
...@@ -89,6 +90,9 @@ static inline char ocfs2_lock_type_char(enum ocfs2_lock_type type) ...@@ -89,6 +90,9 @@ static inline char ocfs2_lock_type_char(enum ocfs2_lock_type type)
case OCFS2_LOCK_TYPE_ORPHAN_SCAN: case OCFS2_LOCK_TYPE_ORPHAN_SCAN:
c = 'P'; c = 'P';
break; break;
case OCFS2_LOCK_TYPE_REFCOUNT:
c = 'T';
break;
default: default:
c = '\0'; c = '\0';
} }
...@@ -110,6 +114,7 @@ static char *ocfs2_lock_type_strings[] = { ...@@ -110,6 +114,7 @@ static char *ocfs2_lock_type_strings[] = {
[OCFS2_LOCK_TYPE_QINFO] = "Quota", [OCFS2_LOCK_TYPE_QINFO] = "Quota",
[OCFS2_LOCK_TYPE_NFS_SYNC] = "NFSSync", [OCFS2_LOCK_TYPE_NFS_SYNC] = "NFSSync",
[OCFS2_LOCK_TYPE_ORPHAN_SCAN] = "OrphanScan", [OCFS2_LOCK_TYPE_ORPHAN_SCAN] = "OrphanScan",
[OCFS2_LOCK_TYPE_REFCOUNT] = "Refcount",
}; };
static inline const char *ocfs2_lock_type_string(enum ocfs2_lock_type type) 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, ...@@ -253,8 +253,9 @@ ssize_t ocfs2_quota_write(struct super_block *sb, int type,
flush_dcache_page(bh->b_page); flush_dcache_page(bh->b_page);
set_buffer_uptodate(bh); set_buffer_uptodate(bh);
unlock_buffer(bh); unlock_buffer(bh);
ocfs2_set_buffer_uptodate(gqinode, bh); ocfs2_set_buffer_uptodate(INODE_CACHE(gqinode), bh);
err = ocfs2_journal_access_dq(handle, gqinode, bh, ja_type); err = ocfs2_journal_access_dq(handle, INODE_CACHE(gqinode), bh,
ja_type);
if (err < 0) { if (err < 0) {
brelse(bh); brelse(bh);
goto out; goto out;
......
...@@ -108,7 +108,7 @@ static int ocfs2_modify_bh(struct inode *inode, struct buffer_head *bh, ...@@ -108,7 +108,7 @@ static int ocfs2_modify_bh(struct inode *inode, struct buffer_head *bh,
mlog_errno(status); mlog_errno(status);
return 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); OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
...@@ -510,7 +510,8 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode, ...@@ -510,7 +510,8 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
goto out_commit; goto out_commit;
} }
/* Release local quota file entry */ /* 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); qbh, OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
...@@ -619,7 +620,8 @@ int ocfs2_finish_quota_recovery(struct ocfs2_super *osb, ...@@ -619,7 +620,8 @@ int ocfs2_finish_quota_recovery(struct ocfs2_super *osb,
mlog_errno(status); mlog_errno(status);
goto out_bh; 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); OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
...@@ -993,8 +995,8 @@ static struct ocfs2_quota_chunk *ocfs2_local_quota_add_chunk( ...@@ -993,8 +995,8 @@ static struct ocfs2_quota_chunk *ocfs2_local_quota_add_chunk(
goto out_trans; goto out_trans;
} }
dchunk = (struct ocfs2_local_disk_chunk *)bh->b_data; dchunk = (struct ocfs2_local_disk_chunk *)bh->b_data;
ocfs2_set_new_buffer_uptodate(lqinode, bh); ocfs2_set_new_buffer_uptodate(INODE_CACHE(lqinode), bh);
status = ocfs2_journal_access_dq(handle, lqinode, bh, status = ocfs2_journal_access_dq(handle, INODE_CACHE(lqinode), bh,
OCFS2_JOURNAL_ACCESS_CREATE); OCFS2_JOURNAL_ACCESS_CREATE);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
...@@ -1027,8 +1029,8 @@ static struct ocfs2_quota_chunk *ocfs2_local_quota_add_chunk( ...@@ -1027,8 +1029,8 @@ static struct ocfs2_quota_chunk *ocfs2_local_quota_add_chunk(
mlog_errno(status); mlog_errno(status);
goto out_trans; goto out_trans;
} }
ocfs2_set_new_buffer_uptodate(lqinode, dbh); ocfs2_set_new_buffer_uptodate(INODE_CACHE(lqinode), dbh);
status = ocfs2_journal_access_dq(handle, lqinode, dbh, status = ocfs2_journal_access_dq(handle, INODE_CACHE(lqinode), dbh,
OCFS2_JOURNAL_ACCESS_CREATE); OCFS2_JOURNAL_ACCESS_CREATE);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
...@@ -1131,7 +1133,7 @@ static struct ocfs2_quota_chunk *ocfs2_extend_local_quota_file( ...@@ -1131,7 +1133,7 @@ static struct ocfs2_quota_chunk *ocfs2_extend_local_quota_file(
mlog_errno(status); mlog_errno(status);
goto out; 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 */ /* Local quota info, chunk header and the new block we initialize */
handle = ocfs2_start_trans(OCFS2_SB(sb), handle = ocfs2_start_trans(OCFS2_SB(sb),
...@@ -1143,7 +1145,7 @@ static struct ocfs2_quota_chunk *ocfs2_extend_local_quota_file( ...@@ -1143,7 +1145,7 @@ static struct ocfs2_quota_chunk *ocfs2_extend_local_quota_file(
goto out; goto out;
} }
/* Zero created block */ /* 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); OCFS2_JOURNAL_ACCESS_CREATE);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
...@@ -1158,7 +1160,8 @@ static struct ocfs2_quota_chunk *ocfs2_extend_local_quota_file( ...@@ -1158,7 +1160,8 @@ static struct ocfs2_quota_chunk *ocfs2_extend_local_quota_file(
goto out_trans; goto out_trans;
} }
/* Update chunk header */ /* 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); OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
...@@ -1292,7 +1295,8 @@ static int ocfs2_local_release_dquot(struct dquot *dquot) ...@@ -1292,7 +1295,8 @@ static int ocfs2_local_release_dquot(struct dquot *dquot)
goto out; 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); od->dq_chunk->qc_headerbh, OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
......
This diff is collapsed.
/* -*- 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, ...@@ -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", mlog_entry("(new_clusters=%d, first_new_cluster = %u)\n",
new_clusters, first_new_cluster); new_clusters, first_new_cluster);
ret = ocfs2_journal_access_gd(handle, bm_inode, group_bh, ret = ocfs2_journal_access_gd(handle, INODE_CACHE(bm_inode),
OCFS2_JOURNAL_ACCESS_WRITE); group_bh, OCFS2_JOURNAL_ACCESS_WRITE);
if (ret < 0) { if (ret < 0) {
mlog_errno(ret); mlog_errno(ret);
goto out; goto out;
...@@ -141,7 +141,7 @@ static int ocfs2_update_last_group_and_inode(handle_t *handle, ...@@ -141,7 +141,7 @@ static int ocfs2_update_last_group_and_inode(handle_t *handle,
} }
/* update the inode accordingly. */ /* 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); OCFS2_JOURNAL_ACCESS_WRITE);
if (ret < 0) { if (ret < 0) {
mlog_errno(ret); mlog_errno(ret);
...@@ -514,7 +514,7 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) ...@@ -514,7 +514,7 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input)
goto out_unlock; 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); ret = ocfs2_verify_group_and_input(main_bm_inode, fe, input, group_bh);
if (ret) { if (ret) {
...@@ -536,8 +536,8 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) ...@@ -536,8 +536,8 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input)
cl = &fe->id2.i_chain; cl = &fe->id2.i_chain;
cr = &cl->cl_recs[input->chain]; cr = &cl->cl_recs[input->chain];
ret = ocfs2_journal_access_gd(handle, main_bm_inode, group_bh, ret = ocfs2_journal_access_gd(handle, INODE_CACHE(main_bm_inode),
OCFS2_JOURNAL_ACCESS_WRITE); group_bh, OCFS2_JOURNAL_ACCESS_WRITE);
if (ret < 0) { if (ret < 0) {
mlog_errno(ret); mlog_errno(ret);
goto out_commit; goto out_commit;
...@@ -552,8 +552,8 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) ...@@ -552,8 +552,8 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input)
goto out_commit; goto out_commit;
} }
ret = ocfs2_journal_access_di(handle, main_bm_inode, main_bm_bh, ret = ocfs2_journal_access_di(handle, INODE_CACHE(main_bm_inode),
OCFS2_JOURNAL_ACCESS_WRITE); main_bm_bh, OCFS2_JOURNAL_ACCESS_WRITE);
if (ret < 0) { if (ret < 0) {
mlog_errno(ret); mlog_errno(ret);
goto out_commit; goto out_commit;
......
...@@ -150,8 +150,8 @@ int ocfs2_refresh_slot_info(struct ocfs2_super *osb) ...@@ -150,8 +150,8 @@ int ocfs2_refresh_slot_info(struct ocfs2_super *osb)
* be !NULL. Thus, ocfs2_read_blocks() will ignore blocknr. If * be !NULL. Thus, ocfs2_read_blocks() will ignore blocknr. If
* this is not true, the read of -1 (UINT64_MAX) will fail. * 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, ret = ocfs2_read_blocks(INODE_CACHE(si->si_inode), -1, si->si_blocks,
OCFS2_BH_IGNORE_CACHE, NULL); si->si_bh, OCFS2_BH_IGNORE_CACHE, NULL);
if (ret == 0) { if (ret == 0) {
spin_lock(&osb->osb_lock); spin_lock(&osb->osb_lock);
ocfs2_update_slot_info(si); ocfs2_update_slot_info(si);
...@@ -213,7 +213,7 @@ static int ocfs2_update_disk_slot(struct ocfs2_super *osb, ...@@ -213,7 +213,7 @@ static int ocfs2_update_disk_slot(struct ocfs2_super *osb,
ocfs2_update_disk_slot_old(si, slot_num, &bh); ocfs2_update_disk_slot_old(si, slot_num, &bh);
spin_unlock(&osb->osb_lock); 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) if (status < 0)
mlog_errno(status); mlog_errno(status);
...@@ -404,8 +404,8 @@ static int ocfs2_map_slot_buffers(struct ocfs2_super *osb, ...@@ -404,8 +404,8 @@ static int ocfs2_map_slot_buffers(struct ocfs2_super *osb,
(unsigned long long)blkno); (unsigned long long)blkno);
bh = NULL; /* Acquire a fresh bh */ bh = NULL; /* Acquire a fresh bh */
status = ocfs2_read_blocks(si->si_inode, blkno, 1, &bh, status = ocfs2_read_blocks(INODE_CACHE(si->si_inode), blkno,
OCFS2_BH_IGNORE_CACHE, NULL); 1, &bh, OCFS2_BH_IGNORE_CACHE, NULL);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
goto bail; goto bail;
......
...@@ -310,7 +310,7 @@ int ocfs2_read_group_descriptor(struct inode *inode, struct ocfs2_dinode *di, ...@@ -310,7 +310,7 @@ int ocfs2_read_group_descriptor(struct inode *inode, struct ocfs2_dinode *di,
int rc; int rc;
struct buffer_head *tmp = *bh; 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); ocfs2_validate_group_descriptor);
if (rc) if (rc)
goto out; goto out;
...@@ -352,7 +352,7 @@ static int ocfs2_block_group_fill(handle_t *handle, ...@@ -352,7 +352,7 @@ static int ocfs2_block_group_fill(handle_t *handle,
} }
status = ocfs2_journal_access_gd(handle, status = ocfs2_journal_access_gd(handle,
alloc_inode, INODE_CACHE(alloc_inode),
bg_bh, bg_bh,
OCFS2_JOURNAL_ACCESS_CREATE); OCFS2_JOURNAL_ACCESS_CREATE);
if (status < 0) { if (status < 0) {
...@@ -476,7 +476,7 @@ static int ocfs2_block_group_alloc(struct ocfs2_super *osb, ...@@ -476,7 +476,7 @@ static int ocfs2_block_group_alloc(struct ocfs2_super *osb,
mlog_errno(status); mlog_errno(status);
goto bail; 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, status = ocfs2_block_group_fill(handle,
alloc_inode, alloc_inode,
...@@ -491,7 +491,7 @@ static int ocfs2_block_group_alloc(struct ocfs2_super *osb, ...@@ -491,7 +491,7 @@ static int ocfs2_block_group_alloc(struct ocfs2_super *osb,
bg = (struct ocfs2_group_desc *) bg_bh->b_data; 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); bh, OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
...@@ -1033,7 +1033,7 @@ static inline int ocfs2_block_group_set_bits(handle_t *handle, ...@@ -1033,7 +1033,7 @@ static inline int ocfs2_block_group_set_bits(handle_t *handle,
journal_type = OCFS2_JOURNAL_ACCESS_UNDO; journal_type = OCFS2_JOURNAL_ACCESS_UNDO;
status = ocfs2_journal_access_gd(handle, status = ocfs2_journal_access_gd(handle,
alloc_inode, INODE_CACHE(alloc_inode),
group_bh, group_bh,
journal_type); journal_type);
if (status < 0) { if (status < 0) {
...@@ -1106,7 +1106,8 @@ static int ocfs2_relink_block_group(handle_t *handle, ...@@ -1106,7 +1106,8 @@ static int ocfs2_relink_block_group(handle_t *handle,
bg_ptr = le64_to_cpu(bg->bg_next_group); bg_ptr = le64_to_cpu(bg->bg_next_group);
prev_bg_ptr = le64_to_cpu(prev_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); OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
...@@ -1121,8 +1122,8 @@ static int ocfs2_relink_block_group(handle_t *handle, ...@@ -1121,8 +1122,8 @@ static int ocfs2_relink_block_group(handle_t *handle,
goto out_rollback; goto out_rollback;
} }
status = ocfs2_journal_access_gd(handle, alloc_inode, bg_bh, status = ocfs2_journal_access_gd(handle, INODE_CACHE(alloc_inode),
OCFS2_JOURNAL_ACCESS_WRITE); bg_bh, OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
goto out_rollback; goto out_rollback;
...@@ -1136,8 +1137,8 @@ static int ocfs2_relink_block_group(handle_t *handle, ...@@ -1136,8 +1137,8 @@ static int ocfs2_relink_block_group(handle_t *handle,
goto out_rollback; goto out_rollback;
} }
status = ocfs2_journal_access_di(handle, alloc_inode, fe_bh, status = ocfs2_journal_access_di(handle, INODE_CACHE(alloc_inode),
OCFS2_JOURNAL_ACCESS_WRITE); fe_bh, OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
goto out_rollback; goto out_rollback;
...@@ -1288,7 +1289,7 @@ static int ocfs2_alloc_dinode_update_counts(struct inode *inode, ...@@ -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_dinode *di = (struct ocfs2_dinode *) di_bh->b_data;
struct ocfs2_chain_list *cl = (struct ocfs2_chain_list *) &di->id2.i_chain; 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); OCFS2_JOURNAL_ACCESS_WRITE);
if (ret < 0) { if (ret < 0) {
mlog_errno(ret); mlog_errno(ret);
...@@ -1461,7 +1462,7 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac, ...@@ -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 /* Ok, claim our bits now: set the info on dinode, chainlist
* and then the group */ * and then the group */
status = ocfs2_journal_access_di(handle, status = ocfs2_journal_access_di(handle,
alloc_inode, INODE_CACHE(alloc_inode),
ac->ac_bh, ac->ac_bh,
OCFS2_JOURNAL_ACCESS_WRITE); OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) { if (status < 0) {
...@@ -1907,8 +1908,8 @@ static inline int ocfs2_block_group_clear_bits(handle_t *handle, ...@@ -1907,8 +1908,8 @@ static inline int ocfs2_block_group_clear_bits(handle_t *handle,
if (ocfs2_is_cluster_bitmap(alloc_inode)) if (ocfs2_is_cluster_bitmap(alloc_inode))
journal_type = OCFS2_JOURNAL_ACCESS_UNDO; journal_type = OCFS2_JOURNAL_ACCESS_UNDO;
status = ocfs2_journal_access_gd(handle, alloc_inode, group_bh, status = ocfs2_journal_access_gd(handle, INODE_CACHE(alloc_inode),
journal_type); group_bh, journal_type);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
goto bail; goto bail;
...@@ -1993,8 +1994,8 @@ int ocfs2_free_suballoc_bits(handle_t *handle, ...@@ -1993,8 +1994,8 @@ int ocfs2_free_suballoc_bits(handle_t *handle,
goto bail; goto bail;
} }
status = ocfs2_journal_access_di(handle, alloc_inode, alloc_bh, status = ocfs2_journal_access_di(handle, INODE_CACHE(alloc_inode),
OCFS2_JOURNAL_ACCESS_WRITE); alloc_bh, OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
goto bail; goto bail;
...@@ -2151,7 +2152,7 @@ int ocfs2_lock_allocators(struct inode *inode, ...@@ -2151,7 +2152,7 @@ int ocfs2_lock_allocators(struct inode *inode,
BUG_ON(clusters_to_add != 0 && data_ac == NULL); 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) { if (num_free_extents < 0) {
ret = num_free_extents; ret = num_free_extents;
mlog_errno(ret); mlog_errno(ret);
......
...@@ -69,6 +69,7 @@ ...@@ -69,6 +69,7 @@
#include "ver.h" #include "ver.h"
#include "xattr.h" #include "xattr.h"
#include "quota.h" #include "quota.h"
#include "refcounttree.h"
#include "buffer_head_io.h" #include "buffer_head_io.h"
...@@ -1668,8 +1669,6 @@ static void ocfs2_inode_init_once(void *data) ...@@ -1668,8 +1669,6 @@ static void ocfs2_inode_init_once(void *data)
spin_lock_init(&oi->ip_lock); spin_lock_init(&oi->ip_lock);
ocfs2_extent_map_init(&oi->vfs_inode); ocfs2_extent_map_init(&oi->vfs_inode);
INIT_LIST_HEAD(&oi->ip_io_markers); INIT_LIST_HEAD(&oi->ip_io_markers);
oi->ip_created_trans = 0;
oi->ip_last_trans = 0;
oi->ip_dir_start_lookup = 0; oi->ip_dir_start_lookup = 0;
init_rwsem(&oi->ip_alloc_sem); init_rwsem(&oi->ip_alloc_sem);
...@@ -1683,7 +1682,8 @@ static void ocfs2_inode_init_once(void *data) ...@@ -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_inode_lockres);
ocfs2_lock_res_init_once(&oi->ip_open_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); inode_init_once(&oi->vfs_inode);
} }
...@@ -1859,6 +1859,8 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err) ...@@ -1859,6 +1859,8 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
ocfs2_sync_blockdev(sb); ocfs2_sync_blockdev(sb);
ocfs2_purge_refcount_trees(osb);
/* No cluster connection means we've failed during mount, so skip /* No cluster connection means we've failed during mount, so skip
* all the steps which depended on that to complete. */ * all the steps which depended on that to complete. */
if (osb->cconn) { if (osb->cconn) {
...@@ -2065,6 +2067,8 @@ static int ocfs2_initialize_super(struct super_block *sb, ...@@ -2065,6 +2067,8 @@ static int ocfs2_initialize_super(struct super_block *sb,
goto bail; goto bail;
} }
osb->osb_rf_lock_tree = RB_ROOT;
osb->s_feature_compat = osb->s_feature_compat =
le32_to_cpu(OCFS2_RAW_SB(di)->s_feature_compat); le32_to_cpu(OCFS2_RAW_SB(di)->s_feature_compat);
osb->s_feature_ro_compat = osb->s_feature_ro_compat =
...@@ -2490,6 +2494,7 @@ void __ocfs2_abort(struct super_block* sb, ...@@ -2490,6 +2494,7 @@ void __ocfs2_abort(struct super_block* sb,
/* Force a panic(). This stinks, but it's better than letting /* Force a panic(). This stinks, but it's better than letting
* things continue without having a proper hard readonly * things continue without having a proper hard readonly
* here. */ * here. */
if (!ocfs2_mount_local(OCFS2_SB(sb)))
OCFS2_SB(sb)->s_mount_opt |= OCFS2_MOUNT_ERRORS_PANIC; OCFS2_SB(sb)->s_mount_opt |= OCFS2_MOUNT_ERRORS_PANIC;
ocfs2_handle_error(sb); ocfs2_handle_error(sb);
} }
......
This diff is collapsed.
...@@ -26,24 +26,59 @@ ...@@ -26,24 +26,59 @@
#ifndef OCFS2_UPTODATE_H #ifndef OCFS2_UPTODATE_H
#define 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); int __init init_ocfs2_uptodate_cache(void);
void exit_ocfs2_uptodate_cache(void); void exit_ocfs2_uptodate_cache(void);
void ocfs2_metadata_cache_init(struct inode *inode); void ocfs2_metadata_cache_init(struct ocfs2_caching_info *ci,
void ocfs2_metadata_cache_purge(struct inode *inode); 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);
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 inode *inode, int ocfs2_buffer_uptodate(struct ocfs2_caching_info *ci,
struct buffer_head *bh); 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); 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); 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); 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, sector_t block,
u32 c_len); 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); struct buffer_head *bh);
#endif /* OCFS2_UPTODATE_H */ #endif /* OCFS2_UPTODATE_H */
This diff is collapsed.
...@@ -55,6 +55,8 @@ int ocfs2_xattr_set_handle(handle_t *, struct inode *, struct buffer_head *, ...@@ -55,6 +55,8 @@ int ocfs2_xattr_set_handle(handle_t *, struct inode *, struct buffer_head *,
int, const char *, const void *, size_t, int, int, const char *, const void *, size_t, int,
struct ocfs2_alloc_context *, struct ocfs2_alloc_context *,
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_xattr_remove(struct inode *, struct buffer_head *);
int ocfs2_init_security_get(struct inode *, struct inode *, int ocfs2_init_security_get(struct inode *, struct inode *,
struct ocfs2_security_xattr_info *); struct ocfs2_security_xattr_info *);
...@@ -83,5 +85,16 @@ struct ocfs2_xattr_value_buf { ...@@ -83,5 +85,16 @@ struct ocfs2_xattr_value_buf {
struct ocfs2_xattr_value_root *vb_xv; 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 */ #endif /* OCFS2_XATTR_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment