* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Whamcloud, Inc.
+ * Copyright (c) 2011, 2014, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
#include <linux/string.h>
#include <linux/quotaops.h>
#include <linux/buffer_head.h>
+
+#include <ldiskfs/ldiskfs.h>
+#include <ldiskfs/xattr.h>
+#undef ENTRY
+
#include "osd_internal.h"
-#include "xattr.h"
-#include "acl.h"
+#include <ldiskfs/acl.h>
/*
* List of all registered formats.
*
* No locking. Callers synchronize.
*/
-static CFS_LIST_HEAD(iam_formats);
+static struct list_head iam_formats = LIST_HEAD_INIT(iam_formats);
void iam_format_register(struct iam_format *fmt)
{
- cfs_list_add(&fmt->if_linkage, &iam_formats);
+ list_add(&fmt->if_linkage, &iam_formats);
}
-EXPORT_SYMBOL(iam_format_register);
static struct buffer_head *
iam_load_idle_blocks(struct iam_container *c, iam_ptr_t blk)
struct buffer_head *bh;
int err;
- LASSERT_SEM_LOCKED(&c->ic_idle_sem);
+ LASSERT(mutex_is_locked(&c->ic_idle_mutex));
if (blk == 0)
return NULL;
}
result = -ENOENT;
- cfs_list_for_each_entry(fmt, &iam_formats, if_linkage) {
+ list_for_each_entry(fmt, &iam_formats, if_linkage) {
result = fmt->if_guess(c);
if (result == 0)
break;
idle_blocks = (__u32 *)(c->ic_root_bh->b_data +
c->ic_descr->id_root_gap +
sizeof(struct dx_countlimit));
- cfs_down(&c->ic_idle_sem);
+ mutex_lock(&c->ic_idle_mutex);
bh = iam_load_idle_blocks(c, le32_to_cpu(*idle_blocks));
if (bh != NULL && IS_ERR(bh))
result = PTR_ERR(bh);
else
c->ic_idle_bh = bh;
- cfs_up(&c->ic_idle_sem);
+ mutex_unlock(&c->ic_idle_mutex);
}
return result;
memset(c, 0, sizeof *c);
c->ic_descr = descr;
c->ic_object = inode;
- cfs_init_rwsem(&c->ic_sem);
+ init_rwsem(&c->ic_sem);
dynlock_init(&c->ic_tree_lock);
- cfs_sema_init(&c->ic_idle_sem, 1);
+ mutex_init(&c->ic_idle_mutex);
return 0;
}
-EXPORT_SYMBOL(iam_container_init);
/*
* Determine container format.
{
return iam_format_guess(c);
}
-EXPORT_SYMBOL(iam_container_setup);
/*
* Finalize container @c, release all resources.
brelse(c->ic_root_bh);
c->ic_root_bh = NULL;
}
-EXPORT_SYMBOL(iam_container_fini);
void iam_path_init(struct iam_path *path, struct iam_container *c,
struct iam_path_descr *pd)
for (i = 0; i < ARRAY_SIZE(path->ip_frames); i++) {
if (path->ip_frames[i].bh != NULL) {
+ path->ip_frames[i].at_shifted = 0;
brelse(path->ip_frames[i].bh);
path->ip_frames[i].bh = NULL;
}
ipd->ipd_key_scratch[i] = karea;
return ipd;
}
-EXPORT_SYMBOL(iam_ipd_alloc);
void iam_ipd_free(struct iam_path_descr *ipd)
{
}
-EXPORT_SYMBOL(iam_ipd_free);
int iam_node_read(struct iam_container *c, iam_ptr_t ptr,
handle_t *h, struct buffer_head **bh)
static int iam_leaf_load(struct iam_path *path)
{
- iam_ptr_t block;
- int err;
- struct iam_container *c;
- struct buffer_head *bh;
- struct iam_leaf *leaf;
- struct iam_descr *descr;
-
- c = path->ip_container;
- leaf = &path->ip_leaf;
- descr = iam_path_descr(path);
- block = path->ip_frame->leaf;
- if (block == 0) {
- /* XXX bug 11027 */
- printk(CFS_KERN_EMERG "wrong leaf: %lu %d [%p %p %p]\n",
- (long unsigned)path->ip_frame->leaf,
- dx_get_count(dx_node_get_entries(path, path->ip_frame)),
- path->ip_frames[0].bh, path->ip_frames[1].bh,
- path->ip_frames[2].bh);
- }
- err = descr->id_ops->id_node_read(c, block, NULL, &bh);
- if (err == 0) {
- leaf->il_bh = bh;
- leaf->il_curidx = block;
- err = iam_leaf_ops(leaf)->init(leaf);
- assert_inv(ergo(err == 0, iam_leaf_check(leaf)));
- }
- return err;
+ iam_ptr_t block;
+ int err;
+ struct iam_container *c;
+ struct buffer_head *bh;
+ struct iam_leaf *leaf;
+ struct iam_descr *descr;
+
+ c = path->ip_container;
+ leaf = &path->ip_leaf;
+ descr = iam_path_descr(path);
+ block = path->ip_frame->leaf;
+ if (block == 0) {
+ /* XXX bug 11027 */
+ printk(KERN_EMERG "wrong leaf: %lu %d [%p %p %p]\n",
+ (long unsigned)path->ip_frame->leaf,
+ dx_get_count(dx_node_get_entries(path, path->ip_frame)),
+ path->ip_frames[0].bh, path->ip_frames[1].bh,
+ path->ip_frames[2].bh);
+ }
+ err = descr->id_ops->id_node_read(c, block, NULL, &bh);
+ if (err == 0) {
+ leaf->il_bh = bh;
+ leaf->il_curidx = block;
+ err = iam_leaf_ops(leaf)->init(leaf);
+ assert_inv(ergo(err == 0, iam_leaf_check(leaf)));
+ }
+ return err;
}
static void iam_unlock_htree(struct iam_container *ic,
return iam_leaf_ops(leaf)->at_end(leaf);
}
-void iam_leaf_split(struct iam_leaf *l, struct buffer_head **bh, iam_ptr_t nr)
+static void iam_leaf_split(struct iam_leaf *l, struct buffer_head **bh,
+ iam_ptr_t nr)
{
iam_leaf_ops(l)->split(l, bh, nr);
}
{
int result;
- result = ldiskfs_journal_dirty_metadata(handle, bh);
+ result = ldiskfs_handle_dirty_metadata(handle, NULL, bh);
if (result != 0)
ldiskfs_std_error(iam_path_obj(path)->i_sb, result);
return result;
void iam_container_write_lock(struct iam_container *ic)
{
- cfs_down_write(&ic->ic_sem);
+ down_write(&ic->ic_sem);
}
void iam_container_write_unlock(struct iam_container *ic)
{
- cfs_up_write(&ic->ic_sem);
+ up_write(&ic->ic_sem);
}
void iam_container_read_lock(struct iam_container *ic)
{
- cfs_down_read(&ic->ic_sem);
+ down_read(&ic->ic_sem);
}
void iam_container_read_unlock(struct iam_container *ic)
{
- cfs_up_read(&ic->ic_sem);
+ up_read(&ic->ic_sem);
}
/*
iam_path_init(&it->ii_path, c, pd);
return 0;
}
-EXPORT_SYMBOL(iam_it_init);
/*
* Finalize iterator and release all resources.
assert_corr(it_state(it) == IAM_IT_DETACHED);
iam_path_fini(&it->ii_path);
}
-EXPORT_SYMBOL(iam_it_fini);
/*
* this locking primitives are used to protect parts
return dynlock_lock(&ic->ic_tree_lock, value, lt, GFP_NOFS);
}
-int iam_index_lock(struct iam_path *path, struct dynlock_handle **lh)
+static int iam_index_lock(struct iam_path *path, struct dynlock_handle **lh)
{
struct iam_frame *f;
*
*/
-struct iam_entry *iam_find_position(struct iam_path *path,
- struct iam_frame *frame)
+static struct iam_entry *iam_find_position(struct iam_path *path,
+ struct iam_frame *frame)
{
int count;
struct iam_entry *p;
* Performs path lookup and returns with found leaf (if any) locked by htree
* lock.
*/
-int iam_lookup_lock(struct iam_path *path,
- struct dynlock_handle **dl, enum dynlock_type lt)
+static int iam_lookup_lock(struct iam_path *path,
+ struct dynlock_handle **dl, enum dynlock_type lt)
{
int result;
- struct inode *dir;
- dir = iam_path_obj(path);
while ((result = __iam_path_lookup(path)) == 0) {
do_corr(schedule());
*dl = iam_lock_htree(path->ip_container, path->ip_frame->leaf,
static int iam_path_lookup(struct iam_path *path, int index)
{
struct iam_container *c;
- struct iam_descr *descr;
struct iam_leaf *leaf;
int result;
c = path->ip_container;
leaf = &path->ip_leaf;
- descr = iam_path_descr(path);
result = iam_lookup_lock(path, &leaf->il_lock, DLT_WRITE);
assert_inv(iam_path_check(path));
do_corr(schedule());
it_keycmp(it, k) <= 0));
return result;
}
-EXPORT_SYMBOL(iam_it_get);
/*
* Attach iterator by index key.
assert_corr(ergo(result >= 0, it_state(it) == IAM_IT_ATTACHED));
return result;
}
-EXPORT_SYMBOL(iam_it_get_at);
/*
* Duplicates iterator.
iam_leaf_fini(&it->ii_path.ip_leaf);
}
}
-EXPORT_SYMBOL(iam_it_put);
static struct iam_ikey *iam_it_ikey_get(const struct iam_iterator *it,
struct iam_ikey *ikey);
int iam_index_next(struct iam_container *c, struct iam_path *path)
{
iam_ptr_t cursor;
- struct dynlock_handle *lh[DX_MAX_TREE_HEIGHT] = { 0, };
+ struct dynlock_handle *lh[DX_MAX_TREE_HEIGHT] = { NULL, };
int result;
struct inode *object;
int result;
struct iam_path *path;
struct iam_leaf *leaf;
- struct inode *obj;
do_corr(struct iam_ikey *ik_orig);
/* assert_corr(it->ii_flags&IAM_IT_MOVE); */
path = &it->ii_path;
leaf = &path->ip_leaf;
- obj = iam_path_obj(path);
assert_corr(iam_leaf_is_locked(leaf));
it_ikeycmp(it, ik_orig) >= 0));
return result;
}
-EXPORT_SYMBOL(iam_it_next);
/*
* Return pointer to the record under iterator.
assert_corr(it_at_rec(it));
return iam_leaf_rec(&it->ii_path.ip_leaf);
}
-EXPORT_SYMBOL(iam_it_rec_get);
static void iam_it_reccpy(struct iam_iterator *it, const struct iam_rec *r)
{
}
return result;
}
-EXPORT_SYMBOL(iam_it_rec_set);
/*
* Return pointer to the index key under iterator.
assert_corr(it_at_rec(it));
return iam_leaf_key(&it->ii_path.ip_leaf);
}
-EXPORT_SYMBOL(iam_it_key_get);
/*
* Return size of key under iterator (in bytes)
assert_corr(it_at_rec(it));
return iam_leaf_key_size(&it->ii_path.ip_leaf);
}
-EXPORT_SYMBOL(iam_it_key_size);
-struct buffer_head *
+static struct buffer_head *
iam_new_node(handle_t *h, struct iam_container *c, iam_ptr_t *b, int *e)
{
struct inode *inode = c->ic_object;
if (c->ic_idle_bh == NULL)
goto newblock;
- cfs_down(&c->ic_idle_sem);
- if (unlikely(c->ic_idle_failed || c->ic_idle_bh == NULL)) {
- cfs_up(&c->ic_idle_sem);
+ mutex_lock(&c->ic_idle_mutex);
+ if (unlikely(c->ic_idle_bh == NULL)) {
+ mutex_unlock(&c->ic_idle_mutex);
goto newblock;
}
--count;
*b = le32_to_cpu(head->iih_blks[count]);
head->iih_count = cpu_to_le16(count);
- *e = ldiskfs_journal_dirty_metadata(h, c->ic_idle_bh);
+ *e = ldiskfs_handle_dirty_metadata(h, inode, c->ic_idle_bh);
if (*e != 0)
goto fail;
- cfs_up(&c->ic_idle_sem);
+ mutex_unlock(&c->ic_idle_mutex);
bh = ldiskfs_bread(NULL, inode, *b, 0, e);
if (bh == NULL)
return NULL;
iam_lock_bh(c->ic_root_bh);
*idle_blocks = head->iih_next;
iam_unlock_bh(c->ic_root_bh);
- *e = ldiskfs_journal_dirty_metadata(h, c->ic_root_bh);
+ *e = ldiskfs_handle_dirty_metadata(h, inode, c->ic_root_bh);
if (*e != 0) {
iam_lock_bh(c->ic_root_bh);
*idle_blocks = cpu_to_le32(*b);
}
c->ic_idle_bh = idle;
- cfs_up(&c->ic_idle_sem);
+ mutex_unlock(&c->ic_idle_mutex);
got:
/* get write access for the found buffer head */
brelse(bh);
bh = NULL;
ldiskfs_std_error(inode->i_sb, *e);
+ } else {
+ /* Clear the reused node as new node does. */
+ memset(bh->b_data, 0, inode->i_sb->s_blocksize);
+ set_buffer_uptodate(bh);
}
return bh;
newblock:
- bh = ldiskfs_append(h, inode, b, e);
+ bh = osd_ldiskfs_append(h, inode, b, e);
return bh;
fail:
- cfs_up(&c->ic_idle_sem);
+ mutex_unlock(&c->ic_idle_mutex);
ldiskfs_std_error(inode->i_sb, *e);
return NULL;
}
struct iam_entry *entries; /* old block contents */
struct iam_entry *entries2; /* new block contents */
- struct iam_frame *frame, *safe;
- struct buffer_head *bh_new[DX_MAX_TREE_HEIGHT] = {0};
+ struct iam_frame *frame, *safe;
+ struct buffer_head *bh_new[DX_MAX_TREE_HEIGHT] = {NULL};
u32 newblock[DX_MAX_TREE_HEIGHT] = {0};
struct dynlock_handle *lock[DX_MAX_TREE_HEIGHT] = {NULL,};
struct dynlock_handle *new_lock[DX_MAX_TREE_HEIGHT] = {NULL,};
++ frame;
assert_inv(dx_node_check(path, frame));
bh_new[0] = NULL; /* buffer head is "consumed" */
- err = ldiskfs_journal_get_write_access(handle, bh2);
+ err = ldiskfs_handle_dirty_metadata(handle, NULL, bh2);
if (err)
goto journal_error;
do_corr(schedule());
dxtrace(dx_show_index ("node", frame->entries));
dxtrace(dx_show_index ("node",
((struct dx_node *) bh2->b_data)->entries));
- err = ldiskfs_journal_dirty_metadata(handle, bh2);
+ err = ldiskfs_handle_dirty_metadata(handle, NULL, bh2);
if (err)
goto journal_error;
do_corr(schedule());
- err = ldiskfs_journal_dirty_metadata(handle, parent->bh);
+ err = ldiskfs_handle_dirty_metadata(handle, NULL,
+ parent->bh);
if (err)
goto journal_error;
}
do_corr(schedule());
- err = ldiskfs_journal_dirty_metadata(handle, bh);
+ err = ldiskfs_handle_dirty_metadata(handle, NULL, bh);
if (err)
goto journal_error;
}
it_keycmp(it, k) == 0));
return result;
}
-EXPORT_SYMBOL(iam_it_rec_insert);
static inline int iam_idle_blocks_limit(struct inode *inode)
{
struct inode *inode = c->ic_object;
struct iam_frame *frame = p->ip_frame;
struct iam_entry *entries;
+ struct iam_entry *pos;
struct dynlock_handle *lh;
int count;
int rc;
iam_lock_bh(frame->bh);
entries = frame->entries;
count = dx_get_count(entries);
+ /* NOT shrink the last entry in the index node, which can be reused
+ * directly by next new node. */
+ if (count == 2) {
+ iam_unlock_bh(frame->bh);
+ iam_unlock_htree(c, lh);
+ return 0;
+ }
+
+ pos = iam_find_position(p, frame);
+ /* There may be some new leaf nodes have been added or empty leaf nodes
+ * have been shrinked during my delete operation.
+ *
+ * If the empty leaf is not under current index node because the index
+ * node has been split, then just skip the empty leaf, which is rare. */
+ if (unlikely(frame->leaf != dx_get_block(p, pos))) {
+ iam_unlock_bh(frame->bh);
+ iam_unlock_htree(c, lh);
+ return 0;
+ }
+
+ frame->at = pos;
if (frame->at < iam_entry_shift(p, entries, count - 1)) {
struct iam_entry *n = iam_entry_shift(p, frame->at, 1);
frame->at_shifted = 1;
}
dx_set_count(entries, count - 1);
- rc = iam_txn_dirty(h, p, frame->bh);
iam_unlock_bh(frame->bh);
+ rc = iam_txn_dirty(h, p, frame->bh);
iam_unlock_htree(c, lh);
if (rc != 0)
return 0;
struct iam_idle_head *head;
int rc;
- rc = iam_txn_add(h, p, bh);
- if (rc != 0)
- return rc;
-
head = (struct iam_idle_head *)(bh->b_data);
head->iih_magic = cpu_to_le16(IAM_IDLE_HEADER_MAGIC);
head->iih_count = 0;
head->iih_next = *idle_blocks;
+ /* The bh already get_write_accessed. */
rc = iam_txn_dirty(h, p, bh);
if (rc != 0)
return rc;
int count;
int rc;
- cfs_down(&c->ic_idle_sem);
+ mutex_lock(&c->ic_idle_mutex);
if (unlikely(c->ic_idle_failed)) {
rc = -EFAULT;
goto unlock;
rc = iam_txn_dirty(h, p, c->ic_idle_bh);
unlock:
- cfs_up(&c->ic_idle_sem);
+ mutex_unlock(&c->ic_idle_mutex);
if (rc != 0)
CWARN("%.16s: idle blocks failed, will lose the blk %u\n",
LDISKFS_SB(inode->i_sb)->s_es->s_volume_name, blk);
it_state(it) == IAM_IT_DETACHED);
return result;
}
-EXPORT_SYMBOL(iam_it_rec_delete);
/*
* Convert iterator to cookie.
result = 0;
return *(iam_pos_t *)iam_it_ikey_get(it, (void *)&result);
}
-EXPORT_SYMBOL(iam_it_store);
/*
* Restore iterator from cookie.
assert_corr(iam_it_container(it)->ic_descr->id_ikey_size <= sizeof pos);
return iam_it_iget(it, (struct iam_ikey *)&pos);
}
-EXPORT_SYMBOL(iam_it_load);
/***********************************************************************/
/* invariants */
return (base <= ptr) && (ptr < base + size);
}
-int iam_frame_invariant(struct iam_frame *f)
+static int iam_frame_invariant(struct iam_frame *f)
{
return
(f->bh != NULL &&
ptr_inside(f->bh->b_data, f->bh->b_size, f->at) &&
f->entries <= f->at);
}
-int iam_leaf_invariant(struct iam_leaf *l)
+
+static int iam_leaf_invariant(struct iam_leaf *l)
{
return
l->il_bh != NULL &&
l->il_entries <= l->il_at;
}
-int iam_path_invariant(struct iam_path *p)
+static int iam_path_invariant(struct iam_path *p)
{
int i;
iam_it_fini(&it);
return result;
}
-EXPORT_SYMBOL(iam_lookup);
/*
* Insert new record @r with key @k into container @c (within context of
iam_it_fini(&it);
return result;
}
-EXPORT_SYMBOL(iam_insert);
/*
* Update record with the key @k in container @c (within context of
iam_it_fini(&it);
return result;
}
-EXPORT_SYMBOL(iam_update);
/*
* Delete existing record with key @k.
iam_it_fini(&it);
return result;
}
-EXPORT_SYMBOL(iam_delete);
int iam_root_limit(int rootgap, int blocksize, int size)
{