aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-08-07 13:10:55 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2010-08-07 13:10:55 -0700
commita57f9a3e811cf1246b394f0cc667c6bc5a52e099 (patch)
tree488b4dd7cd061e7e0e059acb8443967e21051aab
parent09dc942c2a767e2d298f1cc9294bc19c7d7208c5 (diff)
parent89c0fd014d34d409a7b196667c2b9a4813b6c968 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ryusuke/nilfs2
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ryusuke/nilfs2: (45 commits) nilfs2: reject filesystem with unsupported block size nilfs2: avoid rec_len overflow with 64KB block size nilfs2: simplify nilfs_get_page function nilfs2: reject incompatible filesystem nilfs2: add feature set fields to super block nilfs2: clarify byte offset in super block format nilfs2: apply read-ahead for nilfs_btree_lookup_contig nilfs2: introduce check flag to btree node buffer nilfs2: add btree get block function with readahead option nilfs2: add read ahead mode to nilfs_btnode_submit_block nilfs2: fix buffer head leak in nilfs_btnode_submit_block nilfs2: eliminate inline keywords in btree implementation nilfs2: get maximum number of child nodes from bmap object nilfs2: reduce repetitive calculation of max number of child nodes nilfs2: optimize calculation of min/max number of btree node children nilfs2: remove redundant pointer checks in bmap lookup functions nilfs2: get rid of nilfs_bmap_union nilfs2: unify bmap set_target_v operations nilfs2: get rid of nilfs_btree uses nilfs2: get rid of nilfs_direct uses ...
-rw-r--r--Documentation/filesystems/nilfs2.txt12
-rw-r--r--fs/nilfs2/bmap.c6
-rw-r--r--fs/nilfs2/bmap.h16
-rw-r--r--fs/nilfs2/bmap_union.h42
-rw-r--r--fs/nilfs2/btnode.c23
-rw-r--r--fs/nilfs2/btnode.h4
-rw-r--r--fs/nilfs2/btree.c914
-rw-r--r--fs/nilfs2/btree.h12
-rw-r--r--fs/nilfs2/dir.c33
-rw-r--r--fs/nilfs2/direct.c96
-rw-r--r--fs/nilfs2/direct.h11
-rw-r--r--fs/nilfs2/gcinode.c17
-rw-r--r--fs/nilfs2/mdt.c1
-rw-r--r--fs/nilfs2/nilfs.h22
-rw-r--r--fs/nilfs2/page.c5
-rw-r--r--fs/nilfs2/page.h2
-rw-r--r--fs/nilfs2/recovery.c348
-rw-r--r--fs/nilfs2/segbuf.h24
-rw-r--r--fs/nilfs2/segment.c19
-rw-r--r--fs/nilfs2/segment.h10
-rw-r--r--fs/nilfs2/super.c333
-rw-r--r--fs/nilfs2/the_nilfs.c161
-rw-r--r--fs/nilfs2/the_nilfs.h23
-rw-r--r--include/linux/nilfs2_fs.h65
24 files changed, 1294 insertions, 905 deletions
diff --git a/Documentation/filesystems/nilfs2.txt b/Documentation/filesystems/nilfs2.txt
index d3e7673995e..d5c0cef38a7 100644
--- a/Documentation/filesystems/nilfs2.txt
+++ b/Documentation/filesystems/nilfs2.txt
@@ -49,7 +49,10 @@ Mount options
NILFS2 supports the following mount options:
(*) == default
-nobarrier Disables barriers.
+barrier(*) This enables/disables the use of write barriers. This
+nobarrier requires an IO stack which can support barriers, and
+ if nilfs gets an error on a barrier write, it will
+ disable again with a warning.
errors=continue Keep going on a filesystem error.
errors=remount-ro(*) Remount the filesystem read-only on an error.
errors=panic Panic and halt the machine if an error occurs.
@@ -74,9 +77,10 @@ norecovery Disable recovery of the filesystem on mount.
This disables every write access on the device for
read-only mounts or snapshots. This option will fail
for r/w mounts on an unclean volume.
-discard Issue discard/TRIM commands to the underlying block
- device when blocks are freed. This is useful for SSD
- devices and sparse/thinly-provisioned LUNs.
+discard This enables/disables the use of discard/TRIM commands.
+nodiscard(*) The discard/TRIM commands are sent to the underlying
+ block device when blocks are freed. This is useful
+ for SSD devices and sparse/thinly-provisioned LUNs.
NILFS2 usage
============
diff --git a/fs/nilfs2/bmap.c b/fs/nilfs2/bmap.c
index effdbdbe6c1..3dbdc1d356b 100644
--- a/fs/nilfs2/bmap.c
+++ b/fs/nilfs2/bmap.c
@@ -26,6 +26,8 @@
#include "nilfs.h"
#include "bmap.h"
#include "sb.h"
+#include "btree.h"
+#include "direct.h"
#include "btnode.h"
#include "mdt.h"
#include "dat.h"
@@ -533,7 +535,7 @@ void nilfs_bmap_init_gc(struct nilfs_bmap *bmap)
void nilfs_bmap_init_gcdat(struct nilfs_bmap *gcbmap, struct nilfs_bmap *bmap)
{
- memcpy(gcbmap, bmap, sizeof(union nilfs_bmap_union));
+ memcpy(gcbmap, bmap, sizeof(*bmap));
init_rwsem(&gcbmap->b_sem);
lockdep_set_class(&bmap->b_sem, &nilfs_bmap_dat_lock_key);
gcbmap->b_inode = &NILFS_BMAP_I(gcbmap)->vfs_inode;
@@ -541,7 +543,7 @@ void nilfs_bmap_init_gcdat(struct nilfs_bmap *gcbmap, struct nilfs_bmap *bmap)
void nilfs_bmap_commit_gcdat(struct nilfs_bmap *gcbmap, struct nilfs_bmap *bmap)
{
- memcpy(bmap, gcbmap, sizeof(union nilfs_bmap_union));
+ memcpy(bmap, gcbmap, sizeof(*bmap));
init_rwsem(&bmap->b_sem);
lockdep_set_class(&bmap->b_sem, &nilfs_bmap_dat_lock_key);
bmap->b_inode = &NILFS_BMAP_I(bmap)->vfs_inode;
diff --git a/fs/nilfs2/bmap.h b/fs/nilfs2/bmap.h
index 9980d7dbab9..a20569b1992 100644
--- a/fs/nilfs2/bmap.h
+++ b/fs/nilfs2/bmap.h
@@ -32,11 +32,6 @@
#define NILFS_BMAP_INVALID_PTR 0
-#define nilfs_bmap_dkey_to_key(dkey) le64_to_cpu(dkey)
-#define nilfs_bmap_key_to_dkey(key) cpu_to_le64(key)
-#define nilfs_bmap_dptr_to_ptr(dptr) le64_to_cpu(dptr)
-#define nilfs_bmap_ptr_to_dptr(ptr) cpu_to_le64(ptr)
-
#define nilfs_bmap_keydiff_abs(diff) ((diff) < 0 ? -(diff) : (diff))
@@ -71,7 +66,7 @@ struct nilfs_bmap_operations {
int (*bop_delete)(struct nilfs_bmap *, __u64);
void (*bop_clear)(struct nilfs_bmap *);
- int (*bop_propagate)(const struct nilfs_bmap *, struct buffer_head *);
+ int (*bop_propagate)(struct nilfs_bmap *, struct buffer_head *);
void (*bop_lookup_dirty_buffers)(struct nilfs_bmap *,
struct list_head *);
@@ -110,6 +105,7 @@ static inline int nilfs_bmap_is_new_ptr(unsigned long ptr)
* @b_last_allocated_ptr: last allocated ptr for data block
* @b_ptr_type: pointer type
* @b_state: state
+ * @b_nchildren_per_block: maximum number of child nodes for non-root nodes
*/
struct nilfs_bmap {
union {
@@ -123,6 +119,7 @@ struct nilfs_bmap {
__u64 b_last_allocated_ptr;
int b_ptr_type;
int b_state;
+ __u16 b_nchildren_per_block;
};
/* pointer type */
@@ -224,6 +221,13 @@ static inline void nilfs_bmap_abort_end_ptr(struct nilfs_bmap *bmap,
nilfs_dat_abort_end(dat, &req->bpr_req);
}
+static inline void nilfs_bmap_set_target_v(struct nilfs_bmap *bmap, __u64 key,
+ __u64 ptr)
+{
+ bmap->b_last_allocated_key = key;
+ bmap->b_last_allocated_ptr = ptr;
+}
+
__u64 nilfs_bmap_data_get_key(const struct nilfs_bmap *,
const struct buffer_head *);
diff --git a/fs/nilfs2/bmap_union.h b/fs/nilfs2/bmap_union.h
deleted file mode 100644
index d41509bff47..00000000000
--- a/fs/nilfs2/bmap_union.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * bmap_union.h - NILFS block mapping.
- *
- * Copyright (C) 2006-2008 Nippon Telegraph and Telephone Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Written by Koji Sato <koji@osrg.net>.
- */
-
-#ifndef _NILFS_BMAP_UNION_H
-#define _NILFS_BMAP_UNION_H
-
-#include "bmap.h"
-#include "direct.h"
-#include "btree.h"
-
-/**
- * nilfs_bmap_union -
- * @bi_bmap: bmap structure
- * @bi_btree: direct map structure
- * @bi_direct: B-tree structure
- */
-union nilfs_bmap_union {
- struct nilfs_bmap bi_bmap;
- struct nilfs_direct bi_direct;
- struct nilfs_btree bi_btree;
-};
-
-#endif /* _NILFS_BMAP_UNION_H */
diff --git a/fs/nilfs2/btnode.c b/fs/nilfs2/btnode.c
index 447ce47a330..f78ab1044d1 100644
--- a/fs/nilfs2/btnode.c
+++ b/fs/nilfs2/btnode.c
@@ -96,10 +96,12 @@ nilfs_btnode_create_block(struct address_space *btnc, __u64 blocknr)
}
int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr,
- sector_t pblocknr, struct buffer_head **pbh)
+ sector_t pblocknr, int mode,
+ struct buffer_head **pbh, sector_t *submit_ptr)
{
struct buffer_head *bh;
struct inode *inode = NILFS_BTNC_I(btnc);
+ struct page *page;
int err;
bh = nilfs_grab_buffer(inode, btnc, blocknr, 1 << BH_NILFS_Node);
@@ -107,6 +109,7 @@ int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr,
return -ENOMEM;
err = -EEXIST; /* internal code */
+ page = bh->b_page;
if (buffer_uptodate(bh) || buffer_dirty(bh))
goto found;
@@ -125,7 +128,16 @@ int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr,
}
}
}
- lock_buffer(bh);
+
+ if (mode == READA) {
+ if (pblocknr != *submit_ptr + 1 || !trylock_buffer(bh)) {
+ err = -EBUSY; /* internal code */
+ brelse(bh);
+ goto out_locked;
+ }
+ } else { /* mode == READ */
+ lock_buffer(bh);
+ }
if (buffer_uptodate(bh)) {
unlock_buffer(bh);
err = -EEXIST; /* internal code */
@@ -136,15 +148,16 @@ int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr,
bh->b_blocknr = pblocknr; /* set block address for read */
bh->b_end_io = end_buffer_read_sync;
get_bh(bh);
- submit_bh(READ, bh);
+ submit_bh(mode, bh);
bh->b_blocknr = blocknr; /* set back to the given block address */
+ *submit_ptr = pblocknr;
err = 0;
found:
*pbh = bh;
out_locked:
- unlock_page(bh->b_page);
- page_cache_release(bh->b_page);
+ unlock_page(page);
+ page_cache_release(page);
return err;
}
diff --git a/fs/nilfs2/btnode.h b/fs/nilfs2/btnode.h
index 07da83f0771..79037494f1e 100644
--- a/fs/nilfs2/btnode.h
+++ b/fs/nilfs2/btnode.h
@@ -42,8 +42,8 @@ void nilfs_btnode_cache_init(struct address_space *, struct backing_dev_info *);
void nilfs_btnode_cache_clear(struct address_space *);
struct buffer_head *nilfs_btnode_create_block(struct address_space *btnc,
__u64 blocknr);
-int nilfs_btnode_submit_block(struct address_space *, __u64, sector_t,
- struct buffer_head **);
+int nilfs_btnode_submit_block(struct address_space *, __u64, sector_t, int,
+ struct buffer_head **, sector_t *);
void nilfs_btnode_delete(struct buffer_head *);
int nilfs_btnode_prepare_change_key(struct address_space *,
struct nilfs_btnode_chkey_ctxt *);
diff --git a/fs/nilfs2/btree.c b/fs/nilfs2/btree.c
index b27a342c5af..300c2bc00c3 100644
--- a/fs/nilfs2/btree.c
+++ b/fs/nilfs2/btree.c
@@ -66,30 +66,10 @@ static void nilfs_btree_free_path(struct nilfs_btree_path *path)
/*
* B-tree node operations
*/
-static int nilfs_btree_get_block(const struct nilfs_btree *btree, __u64 ptr,
- struct buffer_head **bhp)
-{
- struct address_space *btnc =
- &NILFS_BMAP_I((struct nilfs_bmap *)btree)->i_btnode_cache;
- int err;
-
- err = nilfs_btnode_submit_block(btnc, ptr, 0, bhp);
- if (err)
- return err == -EEXIST ? 0 : err;
-
- wait_on_buffer(*bhp);
- if (!buffer_uptodate(*bhp)) {
- brelse(*bhp);
- return -EIO;
- }
- return 0;
-}
-
-static int nilfs_btree_get_new_block(const struct nilfs_btree *btree,
+static int nilfs_btree_get_new_block(const struct nilfs_bmap *btree,
__u64 ptr, struct buffer_head **bhp)
{
- struct address_space *btnc =
- &NILFS_BMAP_I((struct nilfs_bmap *)btree)->i_btnode_cache;
+ struct address_space *btnc = &NILFS_BMAP_I(btree)->i_btnode_cache;
struct buffer_head *bh;
bh = nilfs_btnode_create_block(btnc, ptr);
@@ -101,71 +81,55 @@ static int nilfs_btree_get_new_block(const struct nilfs_btree *btree,
return 0;
}
-static inline int
-nilfs_btree_node_get_flags(const struct nilfs_btree_node *node)
+static int nilfs_btree_node_get_flags(const struct nilfs_btree_node *node)
{
return node->bn_flags;
}
-static inline void
+static void
nilfs_btree_node_set_flags(struct nilfs_btree_node *node, int flags)
{
node->bn_flags = flags;
}
-static inline int nilfs_btree_node_root(const struct nilfs_btree_node *node)
+static int nilfs_btree_node_root(const struct nilfs_btree_node *node)
{
return nilfs_btree_node_get_flags(node) & NILFS_BTREE_NODE_ROOT;
}
-static inline int
-nilfs_btree_node_get_level(const struct nilfs_btree_node *node)
+static int nilfs_btree_node_get_level(const struct nilfs_btree_node *node)
{
return node->bn_level;
}
-static inline void
+static void
nilfs_btree_node_set_level(struct nilfs_btree_node *node, int level)
{
node->bn_level = level;
}
-static inline int
-nilfs_btree_node_get_nchildren(const struct nilfs_btree_node *node)
+static int nilfs_btree_node_get_nchildren(const struct nilfs_btree_node *node)
{
return le16_to_cpu(node->bn_nchildren);
}
-static inline void
+static void
nilfs_btree_node_set_nchildren(struct nilfs_btree_node *node, int nchildren)
{
node->bn_nchildren = cpu_to_le16(nchildren);
}
-static inline int nilfs_btree_node_size(const struct nilfs_btree *btree)
+static int nilfs_btree_node_size(const struct nilfs_bmap *btree)
{
- return 1 << btree->bt_bmap.b_inode->i_blkbits;
+ return 1 << btree->b_inode->i_blkbits;
}
-static inline int
-nilfs_btree_node_nchildren_min(const struct nilfs_btree_node *node,
- const struct nilfs_btree *btree)
+static int nilfs_btree_nchildren_per_block(const struct nilfs_bmap *btree)
{
- return nilfs_btree_node_root(node) ?
- NILFS_BTREE_ROOT_NCHILDREN_MIN :
- NILFS_BTREE_NODE_NCHILDREN_MIN(nilfs_btree_node_size(btree));
+ return btree->b_nchildren_per_block;
}
-static inline int
-nilfs_btree_node_nchildren_max(const struct nilfs_btree_node *node,
- const struct nilfs_btree *btree)
-{
- return nilfs_btree_node_root(node) ?
- NILFS_BTREE_ROOT_NCHILDREN_MAX :
- NILFS_BTREE_NODE_NCHILDREN_MAX(nilfs_btree_node_size(btree));
-}
-
-static inline __le64 *
+static __le64 *
nilfs_btree_node_dkeys(const struct nilfs_btree_node *node)
{
return (__le64 *)((char *)(node + 1) +
@@ -173,45 +137,40 @@ nilfs_btree_node_dkeys(const struct nilfs_btree_node *node)
0 : NILFS_BTREE_NODE_EXTRA_PAD_SIZE));
}
-static inline __le64 *
-nilfs_btree_node_dptrs(const struct nilfs_btree_node *node,
- const struct nilfs_btree *btree)
+static __le64 *
+nilfs_btree_node_dptrs(const struct nilfs_btree_node *node, int ncmax)
{
- return (__le64 *)(nilfs_btree_node_dkeys(node) +
- nilfs_btree_node_nchildren_max(node, btree));
+ return (__le64 *)(nilfs_btree_node_dkeys(node) + ncmax);
}
-static inline __u64
+static __u64
nilfs_btree_node_get_key(const struct nilfs_btree_node *node, int index)
{
- return nilfs_bmap_dkey_to_key(*(nilfs_btree_node_dkeys(node) + index));
+ return le64_to_cpu(*(nilfs_btree_node_dkeys(node) + index));
}
-static inline void
+static void
nilfs_btree_node_set_key(struct nilfs_btree_node *node, int index, __u64 key)
{
- *(nilfs_btree_node_dkeys(node) + index) = nilfs_bmap_key_to_dkey(key);
+ *(nilfs_btree_node_dkeys(node) + index) = cpu_to_le64(key);
}
-static inline __u64
-nilfs_btree_node_get_ptr(const struct nilfs_btree *btree,
- const struct nilfs_btree_node *node, int index)
+static __u64
+nilfs_btree_node_get_ptr(const struct nilfs_btree_node *node, int index,
+ int ncmax)
{
- return nilfs_bmap_dptr_to_ptr(*(nilfs_btree_node_dptrs(node, btree) +
- index));
+ return le64_to_cpu(*(nilfs_btree_node_dptrs(node, ncmax) + index));
}
-static inline void
-nilfs_btree_node_set_ptr(struct nilfs_btree *btree,
- struct nilfs_btree_node *node, int index, __u64 ptr)
+static void
+nilfs_btree_node_set_ptr(struct nilfs_btree_node *node, int index, __u64 ptr,
+ int ncmax)
{
- *(nilfs_btree_node_dptrs(node, btree) + index) =
- nilfs_bmap_ptr_to_dptr(ptr);
+ *(nilfs_btree_node_dptrs(node, ncmax) + index) = cpu_to_le64(ptr);
}
-static void nilfs_btree_node_init(struct nilfs_btree *btree,
- struct nilfs_btree_node *node,
- int flags, int level, int nchildren,
+static void nilfs_btree_node_init(struct nilfs_btree_node *node, int flags,
+ int level, int nchildren, int ncmax,
const __u64 *keys, const __u64 *ptrs)
{
__le64 *dkeys;
@@ -223,29 +182,28 @@ static void nilfs_btree_node_init(struct nilfs_btree *btree,
nilfs_btree_node_set_nchildren(node, nchildren);
dkeys = nilfs_btree_node_dkeys(node);
- dptrs = nilfs_btree_node_dptrs(node, btree);
+ dptrs = nilfs_btree_node_dptrs(node, ncmax);
for (i = 0; i < nchildren; i++) {
- dkeys[i] = nilfs_bmap_key_to_dkey(keys[i]);
- dptrs[i] = nilfs_bmap_ptr_to_dptr(ptrs[i]);
+ dkeys[i] = cpu_to_le64(keys[i]);
+ dptrs[i] = cpu_to_le64(ptrs[i]);
}
}
/* Assume the buffer heads corresponding to left and right are locked. */
-static void nilfs_btree_node_move_left(struct nilfs_btree *btree,
- struct nilfs_btree_node *left,
+static void nilfs_btree_node_move_left(struct nilfs_btree_node *left,
struct nilfs_btree_node *right,
- int n)
+ int n, int lncmax, int rncmax)
{
__le64 *ldkeys, *rdkeys;
__le64 *ldptrs, *rdptrs;
int lnchildren, rnchildren;
ldkeys = nilfs_btree_node_dkeys(left);
- ldptrs = nilfs_btree_node_dptrs(left, btree);
+ ldptrs = nilfs_btree_node_dptrs(left, lncmax);
lnchildren = nilfs_btree_node_get_nchildren(left);
rdkeys = nilfs_btree_node_dkeys(right);
- rdptrs = nilfs_btree_node_dptrs(right, btree);
+ rdptrs = nilfs_btree_node_dptrs(right, rncmax);
rnchildren = nilfs_btree_node_get_nchildren(right);
memcpy(ldkeys + lnchildren, rdkeys, n * sizeof(*rdkeys));
@@ -260,21 +218,20 @@ static void nilfs_btree_node_move_left(struct nilfs_btree *btree,
}
/* Assume that the buffer heads corresponding to left and right are locked. */
-static void nilfs_btree_node_move_right(struct nilfs_btree *btree,
- struct nilfs_btree_node *left,
+static void nilfs_btree_node_move_right(struct nilfs_btree_node *left,
struct nilfs_btree_node *right,
- int n)
+ int n, int lncmax, int rncmax)
{
__le64 *ldkeys, *rdkeys;
__le64 *ldptrs, *rdptrs;
int lnchildren, rnchildren;
ldkeys = nilfs_btree_node_dkeys(left);
- ldptrs = nilfs_btree_node_dptrs(left, btree);
+ ldptrs = nilfs_btree_node_dptrs(left, lncmax);
lnchildren = nilfs_btree_node_get_nchildren(left);
rdkeys = nilfs_btree_node_dkeys(right);
- rdptrs = nilfs_btree_node_dptrs(right, btree);
+ rdptrs = nilfs_btree_node_dptrs(right, rncmax);
rnchildren = nilfs_btree_node_get_nchildren(right);
memmove(rdkeys + n, rdkeys, rnchildren * sizeof(*rdkeys));
@@ -289,16 +246,15 @@ static void nilfs_btree_node_move_right(struct nilfs_btree *btree,
}
/* Assume that the buffer head corresponding to node is locked. */
-static void nilfs_btree_node_insert(struct nilfs_btree *btree,
- struct nilfs_btree_node *node,
- __u64 key, __u64 ptr, int index)
+static void nilfs_btree_node_insert(struct nilfs_btree_node *node, int index,
+ __u64 key, __u64 ptr, int ncmax)
{
__le64 *dkeys;
__le64 *dptrs;
int nchildren;
dkeys = nilfs_btree_node_dkeys(node);
- dptrs = nilfs_btree_node_dptrs(node, btree);
+ dptrs = nilfs_btree_node_dptrs(node, ncmax);
nchildren = nilfs_btree_node_get_nchildren(node);
if (index < nchildren) {
memmove(dkeys + index + 1, dkeys + index,
@@ -306,16 +262,15 @@ static void nilfs_btree_node_insert(struct nilfs_btree *btree,
memmove(dptrs + index + 1, dptrs + index,
(nchildren - index) * sizeof(*dptrs));
}
- dkeys[index] = nilfs_bmap_key_to_dkey(key);
- dptrs[index] = nilfs_bmap_ptr_to_dptr(ptr);
+ dkeys[index] = cpu_to_le64(key);
+ dptrs[index] = cpu_to_le64(ptr);
nchildren++;
nilfs_btree_node_set_nchildren(node, nchildren);
}
/* Assume that the buffer head corresponding to node is locked. */
-static void nilfs_btree_node_delete(struct nilfs_btree *btree,
- struct nilfs_btree_node *node,
- __u64 *keyp, __u64 *ptrp, int index)
+static void nilfs_btree_node_delete(struct nilfs_btree_node *node, int index,
+ __u64 *keyp, __u64 *ptrp, int ncmax)
{
__u64 key;
__u64 ptr;
@@ -324,9 +279,9 @@ static void nilfs_btree_node_delete(struct nilfs_btree *btree,
int nchildren;
dkeys = nilfs_btree_node_dkeys(node);
- dptrs = nilfs_btree_node_dptrs(node, btree);
- key = nilfs_bmap_dkey_to_key(dkeys[index]);
- ptr = nilfs_bmap_dptr_to_ptr(dptrs[index]);
+ dptrs = nilfs_btree_node_dptrs(node, ncmax);
+ key = le64_to_cpu(dkeys[index]);
+ ptr = le64_to_cpu(dptrs[index]);
nchildren = nilfs_btree_node_get_nchildren(node);
if (keyp != NULL)
*keyp = key;
@@ -382,40 +337,92 @@ static int nilfs_btree_node_lookup(const struct nilfs_btree_node *node,
return s == 0;
}
-static inline struct nilfs_btree_node *
-nilfs_btree_get_root(const struct nilfs_btree *btree)
+/**
+ * nilfs_btree_node_broken - verify consistency of btree node
+ * @node: btree node block to be examined
+ * @size: node size (in bytes)
+ * @blocknr: block number
+ *
+ * Return Value: If node is broken, 1 is returned. Otherwise, 0 is returned.
+ */
+static int nilfs_btree_node_broken(const struct nilfs_btree_node *node,
+ size_t size, sector_t blocknr)
{
- return (struct nilfs_btree_node *)btree->bt_bmap.b_u.u_data;
+ int level, flags, nchildren;
+ int ret = 0;
+
+ level = nilfs_btree_node_get_level(node);
+ flags = nilfs_btree_node_get_flags(node);
+ nchildren = nilfs_btree_node_get_nchildren(node);
+
+ if (unlikely(level < NILFS_BTREE_LEVEL_NODE_MIN ||
+ level >= NILFS_BTREE_LEVEL_MAX ||
+ (flags & NILFS_BTREE_NODE_ROOT) ||
+ nchildren < 0 ||
+ nchildren > NILFS_BTREE_NODE_NCHILDREN_MAX(size))) {
+ printk(KERN_CRIT "NILFS: bad btree node (blocknr=%llu): "
+ "level = %d, flags = 0x%x, nchildren = %d\n",
+ (unsigned long long)blocknr, level, flags, nchildren);
+ ret = 1;
+ }
+ return ret;
}
-static inline struct nilfs_btree_node *
+int nilfs_btree_broken_node_block(struct buffer_head *bh)
+{
+ int ret;
+
+ if (buffer_nilfs_checked(bh))
+ return 0;
+
+ ret = nilfs_btree_node_broken((struct nilfs_btree_node *)bh->b_data,
+ bh->b_size, bh->b_blocknr);
+ if (likely(!ret))
+ set_buffer_nilfs_checked(bh);
+ return ret;
+}
+
+static struct nilfs_btree_node *
+nilfs_btree_get_root(const struct nilfs_bmap *btree)
+{
+ return (struct nilfs_btree_node *)btree->b_u.u_data;
+}
+
+static struct nilfs_btree_node *
nilfs_btree_get_nonroot_node(const struct nilfs_btree_path *path, int level)
{
return (struct nilfs_btree_node *)path[level].bp_bh->b_data;
}
-static inline struct nilfs_btree_node *
+static struct nilfs_btree_node *
nilfs_btree_get_sib_node(const struct nilfs_btree_path *path, int level)
{
return (struct nilfs_btree_node *)path[level].bp_sib_bh->b_data;
}
-static inline int nilfs_btree_height(const struct nilfs_btree *btree)
+static int nilfs_btree_height(const struct nilfs_bmap *btree)
{
return nilfs_btree_node_get_level(nilfs_btree_get_root(btree)) + 1;
}
-static inline struct nilfs_btree_node *
-nilfs_btree_get_node(const struct nilfs_btree *btree,
+static struct nilfs_btree_node *
+nilfs_btree_get_node(const struct nilfs_bmap *btree,
const struct nilfs_btree_path *path,
- int level)
+ int level, int *ncmaxp)
{
- return (level == nilfs_btree_height(btree) - 1) ?
- nilfs_btree_get_root(btree) :
- nilfs_btree_get_nonroot_node(path, level);
+ struct nilfs_btree_node *node;
+
+ if (level == nilfs_btree_height(btree) - 1) {
+ node = nilfs_btree_get_root(btree);
+ *ncmaxp = NILFS_BTREE_ROOT_NCHILDREN_MAX;
+ } else {
+ node = nilfs_btree_get_nonroot_node(path, level);
+ *ncmaxp = nilfs_btree_nchildren_per_block(btree);
+ }
+ return node;
}
-static inline int
+static int
nilfs_btree_bad_node(struct nilfs_btree_node *node, int level)
{
if (unlikely(nilfs_btree_node_get_level(node) != level)) {
@@ -427,13 +434,83 @@ nilfs_btree_bad_node(struct nilfs_btree_node *node, int level)
return 0;
}
-static int nilfs_btree_do_lookup(const struct nilfs_btree *btree,
+struct nilfs_btree_readahead_info {
+ struct nilfs_btree_node *node; /* parent node */
+ int max_ra_blocks; /* max nof blocks to read ahead */
+ int index; /* current index on the parent node */
+ int ncmax; /* nof children in the parent node */
+};
+
+static int __nilfs_btree_get_block(const struct nilfs_bmap *btree, __u64 ptr,
+ struct buffer_head **bhp,
+ const struct nilfs_btree_readahead_info *ra)
+{
+ struct address_space *btnc = &NILFS_BMAP_I(btree)->i_btnode_cache;
+ struct buffer_head *bh, *ra_bh;
+ sector_t submit_ptr = 0;
+ int ret;
+
+ ret = nilfs_btnode_submit_block(btnc, ptr, 0, READ, &bh, &submit_ptr);
+ if (ret) {
+ if (ret != -EEXIST)
+ return ret;
+ goto out_check;
+ }
+
+ if (ra) {
+ int i, n;
+ __u64 ptr2;
+
+ /* read ahead sibling nodes */
+ for (n = ra->max_ra_blocks, i = ra->index + 1;
+ n > 0 && i < ra->ncmax; n--, i++) {
+ ptr2 = nilfs_btree_node_get_ptr(ra->node, i, ra->ncmax);
+
+ ret = nilfs_btnode_submit_block(btnc, ptr2, 0, READA,
+ &ra_bh, &submit_ptr);
+ if (likely(!ret || ret == -EEXIST))
+ brelse(ra_bh);
+ else if (ret != -EBUSY)
+ break;
+ if (!buffer_locked(bh))
+ goto out_no_wait;
+ }
+ }
+
+ wait_on_buffer(bh);
+
+ out_no_wait:
+ if (!buffer_uptodate(bh)) {
+ brelse(bh);
+ return -EIO;
+ }
+
+ out_check:
+ if (nilfs_btree_broken_node_block(bh)) {
+ clear_buffer_uptodate(bh);
+ brelse(bh);
+ return -EINVAL;
+ }
+
+ *bhp = bh;
+ return 0;
+}
+
+static int nilfs_btree_get_block(const struct nilfs_bmap *btree, __u64 ptr,
+ struct buffer_head **bhp)
+{
+ return __nilfs_btree_get_block(btree, ptr, bhp, NULL);
+}
+
+static int nilfs_btree_do_lookup(const struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
- __u64 key, __u64 *ptrp, int minlevel)
+ __u64 key, __u64 *ptrp, int minlevel,
+ int readahead)
{
struct nilfs_btree_node *node;
+ struct nilfs_btree_readahead_info p, *ra;
__u64 ptr;
- int level, index, found, ret;
+ int level, index, found, ncmax, ret;
node = nilfs_btree_get_root(btree);
level = nilfs_btree_node_get_level(node);
@@ -441,14 +518,27 @@ static int nilfs_btree_do_lookup(const struct nilfs_btree *btree,
return -ENOENT;
found = nilfs_btree_node_lookup(node, key, &index);
- ptr = nilfs_btree_node_get_ptr(btree, node, index);
+ ptr = nilfs_btree_node_get_ptr(node, index,
+ NILFS_BTREE_ROOT_NCHILDREN_MAX);
path[level].bp_bh = NULL;
path[level].bp_index = index;
- for (level--; level >= minlevel; level--) {
- ret = nilfs_btree_get_block(btree, ptr, &path[level].bp_bh);
+ ncmax = nilfs_btree_nchildren_per_block(btree);
+
+ while (--level >= minlevel) {
+ ra = NULL;
+ if (level == NILFS_BTREE_LEVEL_NODE_MIN && readahead) {
+ p.node = nilfs_btree_get_node(btree, path, level + 1,
+ &p.ncmax);
+ p.index = index;
+ p.max_ra_blocks = 7;
+ ra = &p;
+ }
+ ret = __nilfs_btree_get_block(btree, ptr, &path[level].bp_bh,
+ ra);
if (ret < 0)
return ret;
+
node = nilfs_btree_get_nonroot_node(path, level);
if (nilfs_btree_bad_node(node, level))
return -EINVAL;
@@ -456,9 +546,9 @@ static int nilfs_btree_do_lookup(const struct nilfs_btree *btree,
found = nilfs_btree_node_lookup(node, key, &index);
else
index = 0;
- if (index < nilfs_btree_node_nchildren_max(node, btree))
- ptr = nilfs_btree_node_get_ptr(btree, node, index);
- else {
+ if (index < ncmax) {
+ ptr = nilfs_btree_node_get_ptr(node, index, ncmax);
+ } else {
WARN_ON(found || level != NILFS_BTREE_LEVEL_NODE_MIN);
/* insert */
ptr = NILFS_BMAP_INVALID_PTR;
@@ -474,22 +564,24 @@ static int nilfs_btree_do_lookup(const struct nilfs_btree *btree,
return 0;
}
-static int nilfs_btree_do_lookup_last(const struct nilfs_btree *btree,
+static int nilfs_btree_do_lookup_last(const struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
__u64 *keyp, __u64 *ptrp)
{
struct nilfs_btree_node *node;
__u64 ptr;
- int index, level, ret;
+ int index, level, ncmax, ret;
node = nilfs_btree_get_root(btree);
index = nilfs_btree_node_get_nchildren(node) - 1;
if (index < 0)
return -ENOENT;
level = nilfs_btree_node_get_level(node);
- ptr = nilfs_btree_node_get_ptr(btree, node, index);
+ ptr = nilfs_btree_node_get_ptr(node, index,
+ NILFS_BTREE_ROOT_NCHILDREN_MAX);
path[level].bp_bh = NULL;
path[level].bp_index = index;
+ ncmax = nilfs_btree_nchildren_per_block(btree);
for (level--; level > 0; level--) {
ret = nilfs_btree_get_block(btree, ptr, &path[level].bp_bh);
@@ -499,7 +591,7 @@ static int nilfs_btree_do_lookup_last(const struct nilfs_btree *btree,
if (nilfs_btree_bad_node(node, level))
return -EINVAL;
index = nilfs_btree_node_get_nchildren(node) - 1;
- ptr = nilfs_btree_node_get_ptr(btree, node, index);
+ ptr = nilfs_btree_node_get_ptr(node, index, ncmax);
path[level].bp_index = index;
}
@@ -511,51 +603,45 @@ static int nilfs_btree_do_lookup_last(const struct nilfs_btree *btree,
return 0;
}
-static int nilfs_btree_lookup(const struct nilfs_bmap *bmap,
+static int nilfs_btree_lookup(const struct nilfs_bmap *btree,
__u64 key, int level, __u64 *ptrp)
{
- struct nilfs_btree *btree;
struct nilfs_btree_path *path;
- __u64 ptr;
int ret;
- btree = (struct nilfs_btree *)bmap;
path = nilfs_btree_alloc_path();
if (path == NULL)
return -ENOMEM;
- ret = nilfs_btree_do_lookup(btree, path, key, &ptr, level);
-
- if (ptrp != NULL)
- *ptrp = ptr;
+ ret = nilfs_btree_do_lookup(btree, path, key, ptrp, level, 0);
nilfs_btree_free_path(path);
return ret;
}
-static int nilfs_btree_lookup_contig(const struct nilfs_bmap *bmap,
+static int nilfs_btree_lookup_contig(const struct nilfs_bmap *btree,
__u64 key, __u64 *ptrp, unsigned maxblocks)
{
- struct nilfs_btree *btree = (struct nilfs_btree *)bmap;
struct nilfs_btree_path *path;
struct nilfs_btree_node *node;
struct inode *dat = NULL;
__u64 ptr, ptr2;
sector_t blocknr;
int level = NILFS_BTREE_LEVEL_NODE_MIN;
- int ret, cnt, index, maxlevel;
+ int ret, cnt, index, maxlevel, ncmax;
+ struct nilfs_btree_readahead_info p;
path = nilfs_btree_alloc_path();
if (path == NULL)
return -ENOMEM;
- ret = nilfs_btree_do_lookup(btree, path, key, &ptr, level);
+ ret = nilfs_btree_do_lookup(btree, path, key, &ptr, level, 1);