Commit a57f9a3e authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 09dc942c 89c0fd01
...@@ -49,7 +49,10 @@ Mount options ...@@ -49,7 +49,10 @@ Mount options
NILFS2 supports the following mount options: NILFS2 supports the following mount options:
(*) == default (*) == 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=continue Keep going on a filesystem error.
errors=remount-ro(*) Remount the filesystem read-only on an error. errors=remount-ro(*) Remount the filesystem read-only on an error.
errors=panic Panic and halt the machine if an error occurs. errors=panic Panic and halt the machine if an error occurs.
...@@ -74,9 +77,10 @@ norecovery Disable recovery of the filesystem on mount. ...@@ -74,9 +77,10 @@ norecovery Disable recovery of the filesystem on mount.
This disables every write access on the device for This disables every write access on the device for
read-only mounts or snapshots. This option will fail read-only mounts or snapshots. This option will fail
for r/w mounts on an unclean volume. for r/w mounts on an unclean volume.
discard Issue discard/TRIM commands to the underlying block discard This enables/disables the use of discard/TRIM commands.
device when blocks are freed. This is useful for SSD nodiscard(*) The discard/TRIM commands are sent to the underlying
devices and sparse/thinly-provisioned LUNs. block device when blocks are freed. This is useful
for SSD devices and sparse/thinly-provisioned LUNs.
NILFS2 usage NILFS2 usage
============ ============
......
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
#include "nilfs.h" #include "nilfs.h"
#include "bmap.h" #include "bmap.h"
#include "sb.h" #include "sb.h"
#include "btree.h"
#include "direct.h"
#include "btnode.h" #include "btnode.h"
#include "mdt.h" #include "mdt.h"
#include "dat.h" #include "dat.h"
...@@ -533,7 +535,7 @@ void nilfs_bmap_init_gc(struct nilfs_bmap *bmap) ...@@ -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) 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); init_rwsem(&gcbmap->b_sem);
lockdep_set_class(&bmap->b_sem, &nilfs_bmap_dat_lock_key); lockdep_set_class(&bmap->b_sem, &nilfs_bmap_dat_lock_key);
gcbmap->b_inode = &NILFS_BMAP_I(gcbmap)->vfs_inode; 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) ...@@ -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) 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); init_rwsem(&bmap->b_sem);
lockdep_set_class(&bmap->b_sem, &nilfs_bmap_dat_lock_key); lockdep_set_class(&bmap->b_sem, &nilfs_bmap_dat_lock_key);
bmap->b_inode = &NILFS_BMAP_I(bmap)->vfs_inode; bmap->b_inode = &NILFS_BMAP_I(bmap)->vfs_inode;
......
...@@ -32,11 +32,6 @@ ...@@ -32,11 +32,6 @@
#define NILFS_BMAP_INVALID_PTR 0 #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)) #define nilfs_bmap_keydiff_abs(diff) ((diff) < 0 ? -(diff) : (diff))
...@@ -71,7 +66,7 @@ struct nilfs_bmap_operations { ...@@ -71,7 +66,7 @@ struct nilfs_bmap_operations {
int (*bop_delete)(struct nilfs_bmap *, __u64); int (*bop_delete)(struct nilfs_bmap *, __u64);
void (*bop_clear)(struct nilfs_bmap *); 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 *, void (*bop_lookup_dirty_buffers)(struct nilfs_bmap *,
struct list_head *); struct list_head *);
...@@ -110,6 +105,7 @@ static inline int nilfs_bmap_is_new_ptr(unsigned long ptr) ...@@ -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_last_allocated_ptr: last allocated ptr for data block
* @b_ptr_type: pointer type * @b_ptr_type: pointer type
* @b_state: state * @b_state: state
* @b_nchildren_per_block: maximum number of child nodes for non-root nodes
*/ */
struct nilfs_bmap { struct nilfs_bmap {
union { union {
...@@ -123,6 +119,7 @@ struct nilfs_bmap { ...@@ -123,6 +119,7 @@ struct nilfs_bmap {
__u64 b_last_allocated_ptr; __u64 b_last_allocated_ptr;
int b_ptr_type; int b_ptr_type;
int b_state; int b_state;
__u16 b_nchildren_per_block;
}; };
/* pointer type */ /* pointer type */
...@@ -224,6 +221,13 @@ static inline void nilfs_bmap_abort_end_ptr(struct nilfs_bmap *bmap, ...@@ -224,6 +221,13 @@ static inline void nilfs_bmap_abort_end_ptr(struct nilfs_bmap *bmap,
nilfs_dat_abort_end(dat, &req->bpr_req); 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 *, __u64 nilfs_bmap_data_get_key(const struct nilfs_bmap *,
const struct buffer_head *); const struct buffer_head *);
......
/*
* 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 */
...@@ -96,10 +96,12 @@ nilfs_btnode_create_block(struct address_space *btnc, __u64 blocknr) ...@@ -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, 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 buffer_head *bh;
struct inode *inode = NILFS_BTNC_I(btnc); struct inode *inode = NILFS_BTNC_I(btnc);
struct page *page;
int err; int err;
bh = nilfs_grab_buffer(inode, btnc, blocknr, 1 << BH_NILFS_Node); 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, ...@@ -107,6 +109,7 @@ int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr,
return -ENOMEM; return -ENOMEM;
err = -EEXIST; /* internal code */ err = -EEXIST; /* internal code */
page = bh->b_page;
if (buffer_uptodate(bh) || buffer_dirty(bh)) if (buffer_uptodate(bh) || buffer_dirty(bh))
goto found; goto found;
...@@ -125,7 +128,16 @@ int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr, ...@@ -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)) { if (buffer_uptodate(bh)) {
unlock_buffer(bh); unlock_buffer(bh);
err = -EEXIST; /* internal code */ err = -EEXIST; /* internal code */
...@@ -136,15 +148,16 @@ int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr, ...@@ -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_blocknr = pblocknr; /* set block address for read */
bh->b_end_io = end_buffer_read_sync; bh->b_end_io = end_buffer_read_sync;
get_bh(bh); get_bh(bh);
submit_bh(READ, bh); submit_bh(mode, bh);
bh->b_blocknr = blocknr; /* set back to the given block address */ bh->b_blocknr = blocknr; /* set back to the given block address */
*submit_ptr = pblocknr;
err = 0; err = 0;
found: found:
*pbh = bh; *pbh = bh;
out_locked: out_locked:
unlock_page(bh->b_page); unlock_page(page);
page_cache_release(bh->b_page); page_cache_release(page);
return err; return err;
} }
......
...@@ -42,8 +42,8 @@ void nilfs_btnode_cache_init(struct address_space *, struct backing_dev_info *); ...@@ -42,8 +42,8 @@ void nilfs_btnode_cache_init(struct address_space *, struct backing_dev_info *);
void nilfs_btnode_cache_clear(struct address_space *); void nilfs_btnode_cache_clear(struct address_space *);
struct buffer_head *nilfs_btnode_create_block(struct address_space *btnc, struct buffer_head *nilfs_btnode_create_block(struct address_space *btnc,
__u64 blocknr); __u64 blocknr);
int nilfs_btnode_submit_block(struct address_space *, __u64, sector_t, int nilfs_btnode_submit_block(struct address_space *, __u64, sector_t, int,
struct buffer_head **); struct buffer_head **, sector_t *);
void nilfs_btnode_delete(struct buffer_head *); void nilfs_btnode_delete(struct buffer_head *);
int nilfs_btnode_prepare_change_key(struct address_space *, int nilfs_btnode_prepare_change_key(struct address_space *,
struct nilfs_btnode_chkey_ctxt *); struct nilfs_btnode_chkey_ctxt *);
......
This diff is collapsed.
...@@ -30,14 +30,6 @@ ...@@ -30,14 +30,6 @@
#include "btnode.h" #include "btnode.h"
#include "bmap.h" #include "bmap.h"
/**
* struct nilfs_btree - B-tree structure
* @bt_bmap: bmap base structure
*/
struct nilfs_btree {
struct nilfs_bmap bt_bmap;
};
/** /**
* struct nilfs_btree_path - A path on which B-tree operations are executed * struct nilfs_btree_path - A path on which B-tree operations are executed
* @bp_bh: buffer head of node block * @bp_bh: buffer head of node block
...@@ -54,7 +46,7 @@ struct nilfs_btree_path { ...@@ -54,7 +46,7 @@ struct nilfs_btree_path {
union nilfs_bmap_ptr_req bp_oldreq; union nilfs_bmap_ptr_req bp_oldreq;
union nilfs_bmap_ptr_req bp_newreq; union nilfs_bmap_ptr_req bp_newreq;
struct nilfs_btnode_chkey_ctxt bp_ctxt; struct nilfs_btnode_chkey_ctxt bp_ctxt;
void (*bp_op)(struct nilfs_btree *, struct nilfs_btree_path *, void (*bp_op)(struct nilfs_bmap *, struct nilfs_btree_path *,
int, __u64 *, __u64 *); int, __u64 *, __u64 *);
}; };
...@@ -80,4 +72,6 @@ int nilfs_btree_convert_and_insert(struct nilfs_bmap *, __u64, __u64, ...@@ -80,4 +72,6 @@ int nilfs_btree_convert_and_insert(struct nilfs_bmap *, __u64, __u64,
const __u64 *, const __u64 *, int); const __u64 *, const __u64 *, int);
void nilfs_btree_init_gc(struct nilfs_bmap *); void nilfs_btree_init_gc(struct nilfs_bmap *);
int nilfs_btree_broken_node_block(struct buffer_head *bh);
#endif /* _NILFS_BTREE_H */ #endif /* _NILFS_BTREE_H */
...@@ -141,7 +141,7 @@ static void nilfs_check_page(struct page *page) ...@@ -141,7 +141,7 @@ static void nilfs_check_page(struct page *page)
} }
for (offs = 0; offs <= limit - NILFS_DIR_REC_LEN(1); offs += rec_len) { for (offs = 0; offs <= limit - NILFS_DIR_REC_LEN(1); offs += rec_len) {
p = (struct nilfs_dir_entry *)(kaddr + offs); p = (struct nilfs_dir_entry *)(kaddr + offs);
rec_len = le16_to_cpu(p->rec_len); rec_len = nilfs_rec_len_from_disk(p->rec_len);
if (rec_len < NILFS_DIR_REC_LEN(1)) if (rec_len < NILFS_DIR_REC_LEN(1))
goto Eshort; goto Eshort;
...@@ -199,13 +199,10 @@ static void nilfs_check_page(struct page *page) ...@@ -199,13 +199,10 @@ static void nilfs_check_page(struct page *page)
static struct page *nilfs_get_page(struct inode *dir, unsigned long n) static struct page *nilfs_get_page(struct inode *dir, unsigned long n)
{ {
struct address_space *mapping = dir->i_mapping; struct address_space *mapping = dir->i_mapping;
struct page *page = read_cache_page(mapping, n, struct page *page = read_mapping_page(mapping, n, NULL);
(filler_t *)mapping->a_ops->readpage, NULL);
if (!IS_ERR(page)) { if (!IS_ERR(page)) {
wait_on_page_locked(page);
kmap(page); kmap(page);
if (!PageUptodate(page))
goto fail;
if (!PageChecked(page)) if (!PageChecked(page))
nilfs_check_page(page); nilfs_check_page(page);
if (PageError(page)) if (PageError(page))
...@@ -238,7 +235,8 @@ nilfs_match(int len, const unsigned char *name, struct nilfs_dir_entry *de) ...@@ -238,7 +235,8 @@ nilfs_match(int len, const unsigned char *name, struct nilfs_dir_entry *de)
*/ */
static struct nilfs_dir_entry *nilfs_next_entry(struct nilfs_dir_entry *p) static struct nilfs_dir_entry *nilfs_next_entry(struct nilfs_dir_entry *p)
{ {
return (struct nilfs_dir_entry *)((char *)p + le16_to_cpu(p->rec_len)); return (struct nilfs_dir_entry *)((char *)p +
nilfs_rec_len_from_disk(p->rec_len));
} }
static unsigned char static unsigned char
...@@ -329,7 +327,7 @@ static int nilfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -329,7 +327,7 @@ static int nilfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
goto success; goto success;
} }
} }
filp->f_pos += le16_to_cpu(de->rec_len); filp->f_pos += nilfs_rec_len_from_disk(de->rec_len);
} }
nilfs_put_page(page); nilfs_put_page(page);
} }
...@@ -444,7 +442,7 @@ void nilfs_set_link(struct inode *dir, struct nilfs_dir_entry *de, ...@@ -444,7 +442,7 @@ void nilfs_set_link(struct inode *dir, struct nilfs_dir_entry *de,
struct page *page, struct inode *inode) struct page *page, struct inode *inode)
{ {
unsigned from = (char *) de - (char *) page_address(page); unsigned from = (char *) de - (char *) page_address(page);
unsigned to = from + le16_to_cpu(de->rec_len); unsigned to = from + nilfs_rec_len_from_disk(de->rec_len);
struct address_space *mapping = page->mapping; struct address_space *mapping = page->mapping;
int err; int err;
...@@ -500,7 +498,7 @@ int nilfs_add_link(struct dentry *dentry, struct inode *inode) ...@@ -500,7 +498,7 @@ int nilfs_add_link(struct dentry *dentry, struct inode *inode)
/* We hit i_size */ /* We hit i_size */
name_len = 0; name_len = 0;
rec_len = chunk_size; rec_len = chunk_size;
de->rec_len = cpu_to_le16(chunk_size); de->rec_len = nilfs_rec_len_to_disk(chunk_size);
de->inode = 0; de->inode = 0;
goto got_it; goto got_it;
} }
...@@ -514,7 +512,7 @@ int nilfs_add_link(struct dentry *dentry, struct inode *inode) ...@@ -514,7 +512,7 @@ int nilfs_add_link(struct dentry *dentry, struct inode *inode)
if (nilfs_match(namelen, name, de)) if (nilfs_match(namelen, name, de))
goto out_unlock; goto out_unlock;
name_len = NILFS_DIR_REC_LEN(de->name_len); name_len = NILFS_DIR_REC_LEN(de->name_len);
rec_len = le16_to_cpu(de->rec_len); rec_len = nilfs_rec_len_from_disk(de->rec_len);
if (!de->inode && rec_len >= reclen) if (!de->inode && rec_len >= reclen)
goto got_it; goto got_it;
if (rec_len >= name_len + reclen) if (rec_len >= name_len + reclen)
...@@ -537,8 +535,8 @@ int nilfs_add_link(struct dentry *dentry, struct inode *inode) ...@@ -537,8 +535,8 @@ int nilfs_add_link(struct dentry *dentry, struct inode *inode)
struct nilfs_dir_entry *de1; struct nilfs_dir_entry *de1;
de1 = (struct nilfs_dir_entry *)((char *)de + name_len); de1 = (struct nilfs_dir_entry *)((char *)de + name_len);
de1->rec_len = cpu_to_le16(rec_len - name_len); de1->rec_len = nilfs_rec_len_to_disk(rec_len - name_len);
de->rec_len = cpu_to_le16(name_len); de->rec_len = nilfs_rec_len_to_disk(name_len);
de = de1; de = de1;
} }
de->name_len = namelen; de->name_len = namelen;
...@@ -569,7 +567,8 @@ int nilfs_delete_entry(struct nilfs_dir_entry *dir, struct page *page) ...@@ -569,7 +567,8 @@ int nilfs_delete_entry(struct nilfs_dir_entry *dir, struct page *page)
struct inode *inode = mapping->host; struct inode *inode = mapping->host;
char *kaddr = page_address(page); char *kaddr = page_address(page);
unsigned from = ((char *)dir - kaddr) & ~(nilfs_chunk_size(inode) - 1); unsigned from = ((char *)dir - kaddr) & ~(nilfs_chunk_size(inode) - 1);
unsigned to = ((char *)dir - kaddr) + le16_to_cpu(dir->rec_len); unsigned to = ((char *)dir - kaddr) +
nilfs_rec_len_from_disk(dir->rec_len);
struct nilfs_dir_entry *pde = NULL; struct nilfs_dir_entry *pde = NULL;
struct nilfs_dir_entry *de = (struct nilfs_dir_entry *)(kaddr + from); struct nilfs_dir_entry *de = (struct nilfs_dir_entry *)(kaddr + from);
int err; int err;
...@@ -590,7 +589,7 @@ int nilfs_delete_entry(struct nilfs_dir_entry *dir, struct page *page) ...@@ -590,7 +589,7 @@ int nilfs_delete_entry(struct nilfs_dir_entry *dir, struct page *page)
err = nilfs_prepare_chunk(page, mapping, from, to); err = nilfs_prepare_chunk(page, mapping, from, to);
BUG_ON(err); BUG_ON(err);
if (pde) if (pde)
pde->rec_len = cpu_to_le16(to - from); pde->rec_len = nilfs_rec_len_to_disk(to - from);
dir->inode = 0; dir->inode = 0;
nilfs_commit_chunk(page, mapping, from, to); nilfs_commit_chunk(page, mapping, from, to);
inode->i_ctime = inode->i_mtime = CURRENT_TIME; inode->i_ctime = inode->i_mtime = CURRENT_TIME;
...@@ -624,14 +623,14 @@ int nilfs_make_empty(struct inode *inode, struct inode *parent) ...@@ -624,14 +623,14 @@ int nilfs_make_empty(struct inode *inode, struct inode *parent)
memset(kaddr, 0, chunk_size); memset(kaddr, 0, chunk_size);
de = (struct nilfs_dir_entry *)kaddr; de = (struct nilfs_dir_entry *)kaddr;
de->name_len = 1; de->name_len = 1;
de->rec_len = cpu_to_le16(NILFS_DIR_REC_LEN(1)); de->rec_len = nilfs_rec_len_to_disk(NILFS_DIR_REC_LEN(1));
memcpy(de->name, ".\0\0", 4); memcpy(de->name, ".\0\0", 4);
de->inode = cpu_to_le64(inode->i_ino); de->inode = cpu_to_le64(inode->i_ino);
nilfs_set_de_type(de, inode); nilfs_set_de_type(de, inode);
de = (struct nilfs_dir_entry *)(kaddr + NILFS_DIR_REC_LEN(1)); de = (struct nilfs_dir_entry *)(kaddr + NILFS_DIR_REC_LEN(1));
de->name_len = 2; de->name_len = 2;
de->rec_len = cpu_to_le16(chunk_size - NILFS_DIR_REC_LEN(1)); de->rec_len = nilfs_rec_len_to_disk(chunk_size - NILFS_DIR_REC_LEN(1));
de->inode = cpu_to_le64(parent->i_ino); de->inode = cpu_to_le64(parent->i_ino);
memcpy(de->name, "..\0", 4); memcpy(de->name, "..\0", 4);
nilfs_set_de_type(de, inode); nilfs_set_de_type(de, inode);
......
This diff is collapsed.
...@@ -28,8 +28,6 @@ ...@@ -28,8 +28,6 @@
#include "bmap.h" #include "bmap.h"
struct nilfs_direct;
/** /**
* struct nilfs_direct_node - direct node * struct nilfs_direct_node - direct node
* @dn_flags: flags * @dn_flags: flags
...@@ -40,15 +38,6 @@ struct nilfs_direct_node { ...@@ -40,15 +38,6 @@ struct nilfs_direct_node {
__u8 pad[7]; __u8 pad[7];
}; };
/**
* struct nilfs_direct - direct mapping
* @d_bmap: bmap structure
*/
struct nilfs_direct {
struct nilfs_bmap d_bmap;
};
#define NILFS_DIRECT_NBLOCKS (NILFS_BMAP_SIZE / sizeof(__le64) - 1) #define NILFS_DIRECT_NBLOCKS (NILFS_BMAP_SIZE / sizeof(__le64) - 1)
#define NILFS_DIRECT_KEY_MIN 0 #define NILFS_DIRECT_KEY_MIN 0
#define NILFS_DIRECT_KEY_MAX (NILFS_DIRECT_NBLOCKS - 1) #define NILFS_DIRECT_KEY_MAX (NILFS_DIRECT_NBLOCKS - 1)
......
...@@ -48,6 +48,8 @@ ...@@ -48,6 +48,8 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/swap.h> #include <linux/swap.h>
#include "nilfs.h" #include "nilfs.h"
#include "btree.h"
#include "btnode.h"
#include "page.h" #include "page.h"
#include "mdt.h" #include "mdt.h"
#include "dat.h" #include "dat.h"
...@@ -149,8 +151,10 @@ int nilfs_gccache_submit_read_data(struct inode *inode, sector_t blkoff, ...@@ -149,8 +151,10 @@ int nilfs_gccache_submit_read_data(struct inode *inode, sector_t blkoff,
int nilfs_gccache_submit_read_node(struct inode *inode, sector_t pbn, int nilfs_gccache_submit_read_node(struct inode *inode, sector_t pbn,
__u64 vbn, struct buffer_head **out_bh) __u64 vbn, struct buffer_head **out_bh)
{ {
int ret = nilfs_btnode_submit_block(&NILFS_I(inode)->i_btnode_cache, int ret;
vbn ? : pbn, pbn, out_bh);
ret = nilfs_btnode_submit_block(&NILFS_I(inode)->i_btnode_cache,
vbn ? : pbn, pbn, READ, out_bh, &pbn);
if (ret == -EEXIST) /* internal code (cache hit) */ if (ret == -EEXIST) /* internal code (cache hit) */
ret = 0; ret = 0;
return ret; return ret;
...@@ -164,10 +168,15 @@ int nilfs_gccache_wait_and_mark_dirty(struct buffer_head *bh) ...@@ -164,10 +168,15 @@ int nilfs_gccache_wait_and_mark_dirty(struct buffer_head *bh)
if (buffer_dirty(bh)) if (buffer_dirty(bh))
return -EEXIST; return -EEXIST;
if (buffer_nilfs_node(bh)) if (buffer_nilfs_node(bh)) {
if (nilfs_btree_broken_node_block(bh)) {
clear_buffer_uptodate(bh);
return -EIO;
}
nilfs_btnode_mark_dirty(bh); nilfs_btnode_mark_dirty(bh);
else } else {
nilfs_mdt_mark_buffer_dirty(bh); nilfs_mdt_mark_buffer_dirty(bh);
}
return 0; return 0;
} }
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/slab.h> #include <linux/slab.h>
#include "nilfs.h" #include "nilfs.h"
#include "btnode.h"
#include "segment.h" #include "segment.h"
#include "page.h" #include "page.h"
#include "mdt.h" #include "mdt.h"
......
...@@ -32,7 +32,6 @@ ...@@ -32,7 +32,6 @@
#include "the_nilfs.h" #include "the_nilfs.h"
#include "sb.h" #include "sb.h"
#include "bmap.h" #include "bmap.h"
#include "bmap_union.h"
/* /*
* nilfs inode data in memory * nilfs inode data in memory
...@@ -41,7 +40,7 @@ struct nilfs_inode_info { ...@@ -41,7 +40,7 @@ struct nilfs_inode_info {
__u32 i_flags; __u32 i_flags;
unsigned long i_state; /* Dynamic state flags */ unsigned long i_state; /* Dynamic state flags */
struct nilfs_bmap *i_bmap; struct nilfs_bmap *i_bmap;
union nilfs_bmap_union i_bmap_union; struct nilfs_bmap i_bmap_data;
__u64 i_xattr; /* sector_t ??? */ __u64 i_xattr; /* sector_t ??? */
__u32 i_dir_start_lookup; __u32 i_dir_start_lookup;
__u64 i_cno; /* check point number for GC inode */ __u64 i_cno; /* check point number for GC inode */
...@@ -71,9 +70,7 @@ static inline struct nilfs_inode_info *NILFS_I(const struct inode *inode) ...@@ -71,9 +70,7 @@ static inline struct nilfs_inode_info *NILFS_I(const struct inode *inode)
static inline struct nilfs_inode_info * static inline struct nilfs_inode_info *
NILFS_BMAP_I(const struct nilfs_bmap *bmap) NILFS_BMAP_I(const struct nilfs_bmap *bmap)
{ {
return container_of((union nilfs_bmap_union *)bmap, return container_of(bmap, struct nilfs_inode_info, i_bmap_data);
struct nilfs_inode_info,
i_bmap_union);
} }
static inline struct inode *NILFS_BTNC_I(struct address_space *btnc) static inline struct inode *NILFS_BTNC_I(struct address_space *btnc)
...@@ -106,6 +103,14 @@ enum { ...@@ -106,6 +103,14 @@ enum {
NILFS_I_GCDAT, /* shadow DAT, on memory only */ NILFS_I_GCDAT, /* shadow DAT, on memory only */
}; };
/*
* commit flags for nilfs_commit_super and nilfs_sync_super
*/
enum {
NILFS_SB_COMMIT = 0, /* Commit a super block alternately */
NILFS_SB_COMMIT_ALL /* Commit both super blocks */
};
/* /*
* Macros to check inode numbers * Macros to check inode numbers
*/ */
...@@ -270,7 +275,14 @@ extern struct nilfs_super_block * ...@@ -270,7 +275,14 @@ extern struct nilfs_super_block *
nilfs_read_super_block(struct super_block *, u64, int, struct buffer_head **); nilfs_read_super_block(struct super_block *, u64, int, struct buffer_head **);
extern int nilfs_store_magic_and_option(struct super_block *, extern int nilfs_store_magic_and_option(struct super_block *,
struct nilfs_super_block *, char *); struct nilfs_super_block *, char *);
extern int nilfs_check_feature_compatibility(struct super_block *,
struct nilfs_super_block *);
extern void nilfs_set_log_cursor(struct nilfs_super_block *,
struct the_nilfs *);
extern struct nilfs_super_block **nilfs_prepare_super(struct nilfs_sb_info *,
int flip);
extern int nilfs_commit_super(struct nilfs_sb_info *, int); extern int nilfs_commit_super(struct nilfs_sb_info *, int);
extern int nilfs_cleanup_super(struct nilfs_sb_info *);
extern int nilfs_attach_checkpoint(struct nilfs_sb_info *, __u64); extern int nilfs_attach_checkpoint(struct nilfs_sb_info *, __u64);
extern void nilfs_detach_checkpoint(struct nilfs_sb_info *); extern void nilfs_detach_checkpoint(struct nilfs_sb_info *);
......
...@@ -37,7 +37,8 @@ ...@@ -37,7 +37,8 @@
#define NILFS_BUFFER_INHERENT_BITS \ #define NILFS_BUFFER_INHERENT_BITS \
((1UL << BH_Uptodate) | (1UL << BH_Mapped) | (1UL << BH_NILFS_Node) | \ ((1UL << BH_Uptodate) | (1UL << BH_Mapped) | (1UL << BH_NILFS_Node) | \
(1UL << BH_NILFS_Volatile) | (1UL << BH_NILFS_Allocated)) (1UL << BH_NILFS_Volatile) | (1UL << BH_NILFS_Allocated) | \
(1UL << BH_NILFS_Checked))
static struct buffer_head * static struct buffer_head *
__nilfs_get_page_block(struct page *page, unsigned long block, pgoff_t index, __nilfs_get_page_block(struct page *page, unsigned long block, pgoff_t index,
...@@ -129,6 +130,7 @@ void nilfs_forget_buffer(struct buffer_head *bh) ...@@ -129,6 +130,7 @@ void nilfs_forget_buffer(struct buffer_head *bh)
lock_buffer(bh); lock_buffer(bh);
clear_buffer_nilfs_volatile(bh); clear_buffer_nilfs_volatile(bh);
clear_buffer_nilfs_checked(bh);
clear_buffer_dirty(bh); clear_buffer_dirty(bh);
if (nilfs_page_buffers_clean(page)) if (nilfs_page_buffers_clean(page))
__nilfs_clear_page_dirty(page); __nilfs_clear_page_dirty(page);
...@@ -480,6 +482,7 @@ void nilfs_clear_dirty_pages(struct address_space *mapping) ...@@ -480,6 +482,7 @@ void nilfs_clear_dirty_pages(struct address_space *mapping)
lock_buffer(bh); lock_buffer(bh);
clear_buffer_dirty(bh); clear_buffer_dirty(bh);
clear_buffer_nilfs_volatile(bh); clear_buffer_nilfs_volatile(bh);
clear_buffer_nilfs_checked(bh);
clear_buffer_uptodate(bh); clear_buffer_uptodate(bh);
clear_buffer_mapped(bh); clear_buffer_mapped(bh);
unlock_buffer(bh); unlock_buffer(bh);
......
...@@ -34,11 +34,13 @@ enum { ...@@ -34,11 +34,13 @@ enum {
BH_NILFS_Allocated = BH_PrivateStart, BH_NILFS_Allocated = BH_PrivateStart,
BH_NILFS_Node, BH_NILFS_Node,
BH_NILFS_Volatile, BH_NILFS_Volatile,
BH_NILFS_Checked,
}; };
BUFFER_FNS(NILFS_Allocated, nilfs_allocated) /* nilfs private buffers */ BUFFER_FNS(NILFS_Allocated, nilfs_allocated) /* nilfs private buffers */
BUFFER_FNS(NILFS_Node, nilfs_node) /* nilfs node buffers */ BUFFER_FNS(NILFS_Node, nilfs_node) /* nilfs node buffers */
BUFFER_FNS(NILFS_Volatile, nilfs_volatile) BUFFER_FNS(NILFS_Volatile, nilfs_volatile)
BUFFER_FNS(NILFS_Checked, nilfs_checked) /* buffer is verified */
void nilfs_mark_buffer_dirty(struct buffer_head *bh); void nilfs_mark_buffer_dirty(struct buffer_head *bh);
......
This diff is collapsed.
...@@ -54,17 +54,6 @@ struct nilfs_segsum_info { ...@@ -54,17 +54,6 @@ struct nilfs_segsum_info {
sector_t next; sector_t next;
}; };
/* macro for the flags */
#define NILFS_SEG_HAS_SR(sum) ((sum)->flags & NILFS_SS_SR)
#define NILFS_SEG_LOGBGN(sum) ((sum)->flags & NILFS_SS_LOGBGN)
#define NILFS_SEG_LOGEND(sum) ((sum)->flags & NILFS_SS_LOGEND)
#define NILFS_SEG_DSYNC(sum) ((sum)->flags & NILFS_SS_SYNDT)
#define NILFS_SEG_SIMPLEX(sum) \
(((sum)->flags & (NILFS_SS_LOGBGN | NILFS_SS_LOGEND)) == \
(NILFS_SS_LOGBGN | NILFS_SS_LOGEND))
#define NILFS_SEG_EMPTY(sum) ((sum)->nblocks == (sum)->nsumblk)
/** /**
* struct nilfs_segment_buffer - Segment buffer * struct nilfs_segment_buffer - Segment buffer
* @sb_super: back pointer to a superblock struct * @sb_super: back pointer to a superblock struct
...@@ -141,6 +130,19 @@ int nilfs_segbuf_extend_payload(struct nilfs_segment_buffer *, ...@@ -141,6 +130,19 @@ int nilfs_segbuf_extend_payload(struct nilfs_segment_buffer *,
struct buffer_head **); struct buffer_head **);
void nilfs_segbuf_fill_in_segsum(struct nilfs_segment_buffer *); void nilfs_segbuf_fill_in_segsum(struct nilfs_segment_buffer *);
static inline int nilfs_segbuf_simplex(struct nilfs_segment_buffer *segbuf)
{
unsigned int flags = segbuf->sb_sum.flags;
return (flags & (NILFS_SS_LOGBGN | NILFS_SS_LOGEND)) ==
(NILFS_SS_LOGBGN | NILFS_SS_LOGEND);
}
static inline int nilfs_segbuf_empty(struct nilfs_segment_buffer *segbuf)
{
return segbuf->sb_sum.nblocks == segbuf->sb_sum.nsumblk;
}
static inline void static inline void
nilfs_segbuf_add_segsum_buffer(struct nilfs_segment_buffer *segbuf, nilfs_segbuf_add_segsum_buffer(struct nilfs_segment_buffer *segbuf,
struct buffer_head *bh) struct buffer_head *bh)
......
...@@ -1914,12 +1914,12 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci) ...@@ -1914,12 +1914,12 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci)
} }
} }
if (!NILFS_SEG_SIMPLEX(&segbuf->sb_sum)) { if (!nilfs_segbuf_simplex(segbuf)) {
if (NILFS_SEG_LOGBGN(&segbuf->sb_sum)) { if (segbuf->sb_sum.flags & NILFS_SS_LOGBGN) {
set_bit(NILFS_SC_UNCLOSED, &sci->sc_flags); set_bit(NILFS_SC_UNCLOSED, &sci->sc_flags);
sci->sc_lseg_stime = jiffies; sci->sc_lseg_stime = jiffies;
} }
if (NILFS_SEG_LOGEND(&segbuf->sb_sum)) if (segbuf->sb_sum.flags & NILFS_SS_LOGEND)
clear_bit(NILFS_SC_UNCLOSED, &sci->sc_flags); clear_bit(NILFS_SC_UNCLOSED, &sci->sc_flags);
} }
} }
...@@ -1951,7 +1951,6 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci) ...@@ -1951,7 +1951,6 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci)
if (update_sr) { if (update_sr) {
nilfs_set_last_segment(nilfs, segbuf->sb_pseg_start, nilfs_set_last_segment(nilfs, segbuf->sb_pseg_start,
segbuf->sb_sum.seg_seq, nilfs->ns_cno++); segbuf->sb_sum.seg_seq, nilfs->ns_cno++);
set_nilfs_sb_dirty(nilfs);
clear_bit(NILFS_SC_HAVE_DELTA, &sci->sc_flags); clear_bit(NILFS_SC_HAVE_DELTA, &sci->sc_flags);
clear_bit(NILFS_SC_DIRTY, &sci->sc_flags); clear_bit(NILFS_SC_DIRTY, &sci->sc_flags);
...@@ -2082,7 +2081,7 @@ static int nilfs_segctor_do_construct(struct nilfs_sc_info *sci, int mode) ...@@ -2082,7 +2081,7 @@ static int nilfs_segctor_do_construct(struct nilfs_sc_info *sci, int mode)
/* Avoid empty segment */ /* Avoid empty segment */
if (sci->sc_stage.scnt == NILFS_ST_DONE && if (sci->sc_stage.scnt == NILFS_ST_DONE &&
NILFS_SEG_EMPTY(&sci->sc_curseg->sb_sum)) { nilfs_segbuf_empty(sci->sc_curseg)) {
nilfs_segctor_abort_construction(sci, nilfs, 1); nilfs_segctor_abort_construction(sci, nilfs, 1);
goto out; goto out;
} }
...@@ -2408,6 +2407,7 @@ static int nilfs_segctor_construct(struct nilfs_sc_info *sci, int mode) ...@@ -2408,6 +2407,7 @@ static int nilfs_segctor_construct(struct nilfs_sc_info *sci, int mode)
{ {
struct nilfs_sb_info *sbi = sci->sc_sbi; struct nilfs_sb_info *sbi = sci->sc_sbi;
struct the_nilfs *nilfs = sbi->s_nilfs; struct the_nilfs *nilfs = sbi->s_nilfs;
struct nilfs_super_block **sbp;
int err = 0; int err = 0;
nilfs_segctor_accept(sci); nilfs_segctor_accept(sci);
...@@ -2423,8 +2423,13 @@ static int nilfs_segctor_construct(struct nilfs_sc_info *sci, int mode) ...@@ -2423,8 +2423,13 @@ static int nilfs_segctor_construct(struct nilfs_sc_info *sci, int mode)
if (test_bit(NILFS_SC_SUPER_ROOT, &sci->sc_flags) && if (test_bit(NILFS_SC_SUPER_ROOT, &sci->sc_flags) &&
nilfs_discontinued(nilfs)) { nilfs_discontinued(nilfs)) {
down_write(&nilfs->ns_sem); down_write(&nilfs->ns_sem);
err = nilfs_commit_super( err = -EIO;
sbi, nilfs_altsb_need_update(nilfs)); sbp = nilfs_prepare_super(sbi,
nilfs_sb_will_flip(nilfs));
if (likely(sbp)) {
nilfs_set_log_cursor(sbp[0], nilfs);
err = nilfs_commit_super(sbi, NILFS_SB_COMMIT);
}
up_write(&nilfs->ns_sem); up_write(&nilfs->ns_sem);
} }
} }
......
...@@ -234,13 +234,13 @@ extern int nilfs_attach_segment_constructor(struct nilfs_sb_info *); ...@@ -234,13 +234,13 @@ extern int nilfs_attach_segment_constructor(struct nilfs_sb_info *);
extern void nilfs_detach_segment_constructor(struct nilfs_sb_info *); extern void nilfs_detach_segment_constructor(struct nilfs_sb_info *);
/* recovery.c */ /* recovery.c */
extern int nilfs_read_super_root_block(struct super_block *, sector_t, extern int nilfs_read_super_root_block(struct the_nilfs *, sector_t,
struct buffer_head **, int); struct buffer_head **, int);
extern int nilfs_search_super_root(struct the_nilfs *, struct nilfs_sb_info *, extern int nilfs_search_super_root(struct the_nilfs *,
struct nilfs_recovery_info *); struct nilfs_recovery_info *);
extern int nilfs_recover_logical_segments(struct the_nilfs *, extern int nilfs_salvage_orphan_logs(struct the_nilfs *,
struct nilfs_sb_info *, struct nilfs_sb_info *,
struct nilfs_recovery_info *); struct nilfs_recovery_info *);
extern void nilfs_dispose_segment_list(struct list_head *); extern void nilfs_dispose_segment_list(struct list_head *);
#endif /* _NILFS_SEGMENT_H */ #endif /* _NILFS_SEGMENT_H */
This diff is collapsed.
...@@ -38,6 +38,8 @@ ...@@ -38,6 +38,8 @@
static LIST_HEAD(nilfs_objects); static LIST_HEAD(nilfs_objects);
static DEFINE_SPINLOCK(nilfs_lock); static DEFINE_SPINLOCK(nilfs_lock);
static int nilfs_valid_sb(struct nilfs_super_block *sbp);
void nilfs_set_last_segment(struct the_nilfs *nilfs, void nilfs_set_last_segment(struct the_nilfs *nilfs,
sector_t start_blocknr, u64 seq, __u64 cno) sector_t start_blocknr, u64 seq, __u64 cno)
{ {
...@@ -45,6 +47,16 @@ void nilfs_set_last_segment(struct the_nilfs *nilfs, ...@@ -45,6 +47,16 @@ void nilfs_set_last_segment(struct the_nilfs *nilfs,
nilfs->ns_last_pseg = start_blocknr; nilfs->ns_last_pseg = start_blocknr;
nilfs->ns_last_seq = seq; nilfs->ns_last_seq = seq;
nilfs->ns_last_cno = cno; nilfs->ns_last_cno = cno;
if (!nilfs_sb_dirty(nilfs)) {
if (nilfs->ns_prev_seq == nilfs->ns_last_seq)
goto stay_cursor;
set_nilfs_sb_dirty(nilfs);
}
nilfs->ns_prev_seq = nilfs->ns_last_seq;
stay_cursor:
spin_unlock(&nilfs->ns_last_segment_lock); spin_unlock(&nilfs->ns_last_segment_lock);
} }
...@@ -159,8 +171,7 @@ void put_nilfs(struct the_nilfs *nilfs) ...@@ -159,8 +171,7 @@ void put_nilfs(struct the_nilfs *nilfs)
kfree(nilfs); kfree(nilfs);
} }
static int nilfs_load_super_root(struct the_nilfs *nilfs, static int nilfs_load_super_root(struct the_nilfs *nilfs, sector_t sr_block)
struct nilfs_sb_info *sbi, sector_t sr_block)
{ {
struct buffer_head *bh_sr; struct buffer_head *bh_sr;
struct nilfs_super_root *raw_sr; struct nilfs_super_root *raw_sr;
...@@ -169,7 +180,7 @@ static int nilfs_load_super_root(struct the_nilfs *nilfs, ...@@ -169,7 +180,7 @@ static int nilfs_load_super_root(struct the_nilfs *nilfs,
unsigned inode_size; unsigned inode_size;
int err; int err;
err = nilfs_read_super_root_block(sbi->s_super, sr_block, &bh_sr, 1); err = nilfs_read_super_root_block(nilfs, sr_block, &bh_sr, 1);
if (unlikely(err)) if (unlikely(err))
return err; return err;
...@@ -247,6 +258,37 @@ static void nilfs_clear_recovery_info(struct nilfs_recovery_info *ri) ...@@ -247,6 +258,37 @@ static void nilfs_clear_recovery_info(struct nilfs_recovery_info *ri)
nilfs_dispose_segment_list(&ri->ri_used_segments); nilfs_dispose_segment_list(&ri->ri_used_segments);
} }
/**
* nilfs_store_log_cursor - load log cursor from a super block
* @nilfs: nilfs object
* @sbp: buffer storing super block to be read
*
* nilfs_store_log_cursor() reads the last position of the log
* containing a super root from a given super block, and initializes
* relevant information on the nilfs object preparatory for log
* scanning and recovery.
*/
static int nilfs_store_log_cursor(struct the_nilfs *nilfs,
struct nilfs_super_block *sbp)
{
int ret = 0;
nilfs->ns_last_pseg = le64_to_cpu(sbp->s_last_pseg);
nilfs->ns_last_cno = le64_to_cpu(sbp->s_last_cno);
nilfs->ns_last_seq = le64_to_cpu(sbp->s_last_seq);
nilfs->ns_prev_seq = nilfs->ns_last_seq;
nilfs->ns_seg_seq = nilfs->ns_last_seq;
nilfs->ns_segnum =
nilfs_get_segnum_of_block(nilfs, nilfs->ns_last_pseg);
nilfs->ns_cno = nilfs->ns_last_cno + 1;
if (nilfs->ns_segnum >= nilfs->ns_nsegments) {
printk(KERN_ERR "NILFS invalid last segment number.\n");
ret = -EINVAL;
}
return ret;
}
/** /**
* load_nilfs - load and recover the nilfs * load_nilfs - load and recover the nilfs
* @nilfs: the_nilfs structure to be released * @nilfs: the_nilfs structure to be released
...@@ -285,13 +327,55 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) ...@@ -285,13 +327,55 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)
nilfs_init_recovery_info(&ri); nilfs_init_recovery_info(&ri);
err = nilfs_search_super_root(nilfs, sbi, &ri); err = nilfs_search_super_root(nilfs, &ri);
if (unlikely(err)) { if (unlikely(err)) {
printk(KERN_ERR "NILFS: error searching super root.\n"); struct nilfs_super_block **sbp = nilfs->ns_sbp;
goto failed; int blocksize;
if (err != -EINVAL)
goto scan_error;
if (!nilfs_valid_sb(sbp[1])) {
printk(KERN_WARNING
"NILFS warning: unable to fall back to spare"
"super block\n");
goto scan_error;
}
printk(KERN_INFO
"NILFS: try rollback from an earlier position\n");
/*
* restore super block with its spare and reconfigure
* relevant states of the nilfs object.
*/
memcpy(sbp[0], sbp[1], nilfs->ns_sbsize);
nilfs->ns_crc_seed = le32_to_cpu(sbp[0]->s_crc_seed);
nilfs->ns_sbwtime = le64_to_cpu(sbp[0]->s_wtime);
/* verify consistency between two super blocks */
blocksize = BLOCK_SIZE << le32_to_cpu(sbp[0]->s_log_block_size);
if (blocksize != nilfs->ns_blocksize) {
printk(KERN_WARNING
"NILFS warning: blocksize differs between "
"two super blocks (%d != %d)\n",
blocksize, nilfs->ns_blocksize);
goto scan_error;
}
err = nilfs_store_log_cursor(nilfs, sbp[0]);
if (err)
goto scan_error;
/* drop clean flag to allow roll-forward and recovery */
nilfs->ns_mount_state &= ~NILFS_VALID_FS;
valid_fs = 0;
err = nilfs_search_super_root(nilfs, &ri);
if (err)
goto scan_error;
} }
err = nilfs_load_super_root(nilfs, sbi, ri.ri_super_root); err = nilfs_load_super_root(nilfs, ri.ri_super_root);
if (unlikely(err)) { if (unlikely(err)) {
printk(KERN_ERR "NILFS: error loading super root.\n"); printk(KERN_ERR "NILFS: error loading super root.\n");
goto failed; goto failed;
...@@ -301,11 +385,23 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) ...@@ -301,11 +385,23 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)
goto skip_recovery; goto skip_recovery;
if (s_flags & MS_RDONLY) { if (s_flags & MS_RDONLY) {
__u64 features;
if (nilfs_test_opt(sbi, NORECOVERY)) { if (nilfs_test_opt(sbi, NORECOVERY)) {
printk(KERN_INFO "NILFS: norecovery option specified. " printk(KERN_INFO "NILFS: norecovery option specified. "
"skipping roll-forward recovery\n"); "skipping roll-forward recovery\n");
goto skip_recovery; goto skip_recovery;
} }
features = le64_to_cpu(nilfs->ns_sbp[0]->s_feature_compat_ro) &
~NILFS_FEATURE_COMPAT_RO_SUPP;
if (features) {
printk(KERN_ERR "NILFS: couldn't proceed with "
"recovery because of unsupported optional "
"features (%llx)\n",
(unsigned long long)features);
err = -EROFS;
goto failed_unload;
}
if (really_read_only) { if (really_read_only) {
printk(KERN_ERR "NILFS: write access " printk(KERN_ERR "NILFS: write access "
"unavailable, cannot proceed.\n"); "unavailable, cannot proceed.\n");
...@@ -320,14 +416,13 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) ...@@ -320,14 +416,13 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)
goto failed_unload; goto failed_unload;
} }
err = nilfs_recover_logical_segments(nilfs, sbi, &ri); err = nilfs_salvage_orphan_logs(nilfs, sbi, &ri);
if (err) if (err)
goto failed_unload; goto failed_unload;
down_write(&nilfs->ns_sem); down_write(&nilfs->ns_sem);
nilfs->ns_mount_state |= NILFS_VALID_FS; nilfs->ns_mount_state |= NILFS_VALID_FS; /* set "clean" flag */
nilfs->ns_sbp[0]->s_state = cpu_to_le16(nilfs->ns_mount_state); err = nilfs_cleanup_super(sbi);
err = nilfs_commit_super(sbi, 1);
up_write(&nilfs->ns_sem); up_write(&nilfs->ns_sem);
if (err) { if (err) {
...@@ -343,6 +438,10 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) ...@@ -343,6 +438,10 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)
sbi->s_super->s_flags = s_flags; sbi->s_super->s_flags = s_flags;
return 0; return 0;
scan_error:
printk(KERN_ERR "NILFS: error searching super root.\n");
goto failed;
failed_unload: failed_unload:
nilfs_mdt_destroy(nilfs->ns_cpfile); nilfs_mdt_destroy(nilfs->ns_cpfile);
nilfs_mdt_destroy(nilfs->ns_sufile); nilfs_mdt_destroy(nilfs->ns_sufile);
...@@ -515,8 +614,8 @@ static int nilfs_load_super_block(struct the_nilfs *nilfs, ...@@ -515,8 +614,8 @@ static int nilfs_load_super_block(struct the_nilfs *nilfs,
nilfs_swap_super_block(nilfs); nilfs_swap_super_block(nilfs);
} }
nilfs->ns_sbwtime[0] = le64_to_cpu(sbp[0]->s_wtime); nilfs->ns_sbwcount = 0;
nilfs->ns_sbwtime[1] = valid[!swp] ? le64_to_cpu(sbp[1]->s_wtime) : 0; nilfs->ns_sbwtime = le64_to_cpu(sbp[0]->s_wtime);
nilfs->ns_prot_seq = le64_to_cpu(sbp[valid[1] & !swp]->s_last_seq); nilfs->ns_prot_seq = le64_to_cpu(sbp[valid[1] & !swp]->s_last_seq);
*sbpp = sbp[0]; *sbpp = sbp[0];
return 0; return 0;
...@@ -557,6 +656,10 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) ...@@ -557,6 +656,10 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
if (err) if (err)
goto out; goto out;
err = nilfs_check_feature_compatibility(sb, sbp);
if (err)
goto out;
blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size); blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size);
if (sb->s_blocksize != blocksize && if (sb->s_blocksize != blocksize &&
!sb_set_blocksize(sb, blocksize)) { !sb_set_blocksize(sb, blocksize)) {
...@@ -568,7 +671,7 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) ...@@ -568,7 +671,7 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
goto out; goto out;
} }
blocksize = sb_min_blocksize(sb, BLOCK_SIZE); blocksize = sb_min_blocksize(sb, NILFS_MIN_BLOCK_SIZE);
if (!blocksize) { if (!blocksize) {
printk(KERN_ERR "NILFS: unable to set blocksize\n"); printk(KERN_ERR "NILFS: unable to set blocksize\n");
err = -EINVAL; err = -EINVAL;
...@@ -582,7 +685,18 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) ...@@ -582,7 +685,18 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
if (err) if (err)
goto failed_sbh; goto failed_sbh;
err = nilfs_check_feature_compatibility(sb, sbp);
if (err)
goto failed_sbh;
blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size); blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size);
if (blocksize < NILFS_MIN_BLOCK_SIZE ||
blocksize > NILFS_MAX_BLOCK_SIZE) {
printk(KERN_ERR "NILFS: couldn't mount because of unsupported "
"filesystem blocksize %d\n", blocksize);
err = -EINVAL;
goto failed_sbh;
}
if (sb->s_blocksize != blocksize) { if (sb->s_blocksize != blocksize) {
int hw_blocksize = bdev_logical_block_size(sb->s_bdev); int hw_blocksize = bdev_logical_block_size(sb->s_bdev);
...@@ -604,6 +718,7 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) ...@@ -604,6 +718,7 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
when reloading fails. */ when reloading fails. */
} }
nilfs->ns_blocksize_bits = sb->s_blocksize_bits; nilfs->ns_blocksize_bits = sb->s_blocksize_bits;
nilfs->ns_blocksize = blocksize;
err = nilfs_store_disk_layout(nilfs, sbp); err = nilfs_store_disk_layout(nilfs, sbp);
if (err) if (err)
...@@ -616,23 +731,9 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) ...@@ -616,23 +731,9 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
bdi = nilfs->ns_bdev->bd_inode->i_mapping->backing_dev_info; bdi = nilfs->ns_bdev->bd_inode->i_mapping->backing_dev_info;
nilfs->ns_bdi = bdi ? : &default_backing_dev_info; nilfs->ns_bdi = bdi ? : &default_backing_dev_info;
/* Finding last segment */ err = nilfs_store_log_cursor(nilfs, sbp);
nilfs->ns_last_pseg = le64_to_cpu(sbp->s_last_pseg); if (err)
nilfs->ns_last_cno = le64_to_cpu(sbp->s_last_cno);
nilfs->ns_last_seq = le64_to_cpu(sbp->s_last_seq);
nilfs->ns_seg_seq = nilfs->ns_last_seq;
nilfs->ns_segnum =
nilfs_get_segnum_of_block(nilfs, nilfs->ns_last_pseg);
nilfs->ns_cno = nilfs->ns_last_cno + 1;
if (nilfs->ns_segnum >= nilfs->ns_nsegments) {
printk(KERN_ERR "NILFS invalid last segment number.\n");
err = -EINVAL;
goto failed_sbh; goto failed_sbh;
}
/* Dummy values */
nilfs->ns_free_segments_count =
nilfs->ns_nsegments - (nilfs->ns_segnum + 1);
/* Initialize gcinode cache */ /* Initialize gcinode cache */
err = nilfs_init_gccache(nilfs); err = nilfs_init_gccache(nilfs);
......
...@@ -57,7 +57,8 @@ enum { ...@@ -57,7 +57,8 @@ enum {
* @ns_current: back pointer to current mount * @ns_current: back pointer to current mount
* @ns_sbh: buffer heads of on-disk super blocks * @ns_sbh: buffer heads of on-disk super blocks
* @ns_sbp: pointers to super block data * @ns_sbp: pointers to super block data
* @ns_sbwtime: previous write time of super blocks * @ns_sbwtime: previous write time of super block
* @ns_sbwcount: write count of super block
* @ns_sbsize: size of valid data in super block * @ns_sbsize: size of valid data in super block
* @ns_supers: list of nilfs super block structs * @ns_supers: list of nilfs super block structs
* @ns_seg_seq: segment sequence counter * @ns_seg_seq: segment sequence counter
...@@ -73,7 +74,7 @@ enum { ...@@ -73,7 +74,7 @@ enum {
* @ns_last_seq: sequence value of the latest segment * @ns_last_seq: sequence value of the latest segment
* @ns_last_cno: checkpoint number of the latest segment * @ns_last_cno: checkpoint number of the latest segment
* @ns_prot_seq: least sequence number of segments which must not be reclaimed * @ns_prot_seq: least sequence number of segments which must not be reclaimed
* @ns_free_segments_count: counter of free segments * @ns_prev_seq: base sequence number used to decide if advance log cursor
* @ns_segctor_sem: segment constructor semaphore * @ns_segctor_sem: segment constructor semaphore
* @ns_dat: DAT file inode * @ns_dat: DAT file inode
* @ns_cpfile: checkpoint file inode * @ns_cpfile: checkpoint file inode
...@@ -82,6 +83,7 @@ enum { ...@@ -82,6 +83,7 @@ enum {
* @ns_gc_inodes: dummy inodes to keep live blocks * @ns_gc_inodes: dummy inodes to keep live blocks
* @ns_gc_inodes_h: hash list to keep dummy inode holding live blocks * @ns_gc_inodes_h: hash list to keep dummy inode holding live blocks
* @ns_blocksize_bits: bit length of block size * @ns_blocksize_bits: bit length of block size
* @ns_blocksize: block size
* @ns_nsegments: number of segments in filesystem * @ns_nsegments: number of segments in filesystem
* @ns_blocks_per_segment: number of blocks per segment * @ns_blocks_per_segment: number of blocks per segment
* @ns_r_segments_percentage: reserved segments percentage * @ns_r_segments_percentage: reserved segments percentage
...@@ -119,7 +121,8 @@ struct the_nilfs { ...@@ -119,7 +121,8 @@ struct the_nilfs {
*/ */
struct buffer_head *ns_sbh[2]; struct buffer_head *ns_sbh[2];
struct nilfs_super_block *ns_sbp[2]; struct nilfs_super_block *ns_sbp[2];
time_t ns_sbwtime[2]; time_t ns_sbwtime;
unsigned ns_sbwcount;
unsigned ns_sbsize; unsigned ns_sbsize;
unsigned ns_mount_state; unsigned ns_mount_state;
...@@ -149,7 +152,7 @@ struct the_nilfs { ...@@ -149,7 +152,7 @@ struct the_nilfs {
u64 ns_last_seq; u64 ns_last_seq;
__u64 ns_last_cno; __u64 ns_last_cno;
u64 ns_prot_seq; u64 ns_prot_seq;
unsigned long ns_free_segments_count; u64 ns_prev_seq;
struct rw_semaphore ns_segctor_sem; struct rw_semaphore ns_segctor_sem;
...@@ -168,6 +171,7 @@ struct the_nilfs { ...@@ -168,6 +171,7 @@ struct the_nilfs {
/* Disk layout information (static) */ /* Disk layout information (static) */
unsigned int ns_blocksize_bits; unsigned int ns_blocksize_bits;
unsigned int ns_blocksize;
unsigned long ns_nsegments; unsigned long ns_nsegments;
unsigned long ns_blocks_per_segment; unsigned long ns_blocks_per_segment;
unsigned long ns_r_segments_percentage; unsigned long ns_r_segments_percentage;
...@@ -203,20 +207,17 @@ THE_NILFS_FNS(SB_DIRTY, sb_dirty) ...@@ -203,20 +207,17 @@ THE_NILFS_FNS(SB_DIRTY, sb_dirty)
/* Minimum interval of periodical update of superblocks (in seconds) */ /* Minimum interval of periodical update of superblocks (in seconds) */
#define NILFS_SB_FREQ 10 #define NILFS_SB_FREQ 10
#define NILFS_ALTSB_FREQ 60 /* spare superblock */
static inline int nilfs_sb_need_update(struct the_nilfs *nilfs) static inline int nilfs_sb_need_update(struct the_nilfs *nilfs)
{ {
u64 t = get_seconds(); u64 t = get_seconds();
return t < nilfs->ns_sbwtime[0] || return t < nilfs->ns_sbwtime || t > nilfs->ns_sbwtime + NILFS_SB_FREQ;
t > nilfs->ns_sbwtime[0] + NILFS_SB_FREQ;
} }
static inline int nilfs_altsb_need_update(struct the_nilfs *nilfs) static inline int nilfs_sb_will_flip(struct the_nilfs *nilfs)
{ {
u64 t = get_seconds(); int flip_bits = nilfs->ns_sbwcount & 0x0FL;
struct nilfs_super_block **sbp = nilfs->ns_sbp; return (flip_bits != 0x08 && flip_bits != 0x0F);
return sbp[1] && t > nilfs->ns_sbwtime[1] + NILFS_ALTSB_FREQ;
} }
void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64); void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64);
......
...@@ -160,7 +160,7 @@ struct nilfs_super_root { ...@@ -160,7 +160,7 @@ struct nilfs_super_root {
* struct nilfs_super_block - structure of super block on disk * struct nilfs_super_block - structure of super block on disk
*/ */
struct nilfs_super_block { struct nilfs_super_block {
__le32 s_rev_level; /* Revision level */ /*00*/ __le32 s_rev_level; /* Revision level */
__le16 s_minor_rev_level; /* minor revision level */ __le16 s_minor_rev_level; /* minor revision level */
__le16 s_magic; /* Magic signature */ __le16 s_magic; /* Magic signature */
...@@ -169,50 +169,53 @@ struct nilfs_super_block { ...@@ -169,50 +169,53 @@ struct nilfs_super_block {
is excluded. */ is excluded. */
__le16 s_flags; /* flags */ __le16 s_flags; /* flags */
__le32 s_crc_seed; /* Seed value of CRC calculation */ __le32 s_crc_seed; /* Seed value of CRC calculation */
__le32 s_sum; /* Check sum of super block */ /*10*/ __le32 s_sum; /* Check sum of super block */
__le32 s_log_block_size; /* Block size represented as follows __le32 s_log_block_size; /* Block size represented as follows
blocksize = blocksize =
1 << (s_log_block_size + 10) */ 1 << (s_log_block_size + 10) */
__le64 s_nsegments; /* Number of segments in filesystem */ __le64 s_nsegments; /* Number of segments in filesystem */
__le64 s_dev_size; /* block device size in bytes */ /*20*/ __le64 s_dev_size; /* block device size in bytes */
__le64 s_first_data_block; /* 1st seg disk block number */ __le64 s_first_data_block; /* 1st seg disk block number */
__le32 s_blocks_per_segment; /* number of blocks per full segment */ /*30*/ __le32 s_blocks_per_segment; /* number of blocks per full segment */
__le32 s_r_segments_percentage; /* Reserved segments percentage */ __le32 s_r_segments_percentage; /* Reserved segments percentage */
__le64 s_last_cno; /* Last checkpoint number */ __le64 s_last_cno; /* Last checkpoint number */
__le64 s_last_pseg; /* disk block addr pseg written last */ /*40*/ __le64 s_last_pseg; /* disk block addr pseg written last */
__le64 s_last_seq; /* seq. number of seg written last */ __le64 s_last_seq; /* seq. number of seg written last */
__le64 s_free_blocks_count; /* Free blocks count */ /*50*/ __le64 s_free_blocks_count; /* Free blocks count */
__le64 s_ctime; /* Creation time (execution time of __le64 s_ctime; /* Creation time (execution time of
newfs) */ newfs) */
__le64 s_mtime; /* Mount time */ /*60*/ __le64 s_mtime; /* Mount time */
__le64 s_wtime; /* Write time */ __le64 s_wtime; /* Write time */
__le16 s_mnt_count; /* Mount count */ /*70*/ __le16 s_mnt_count; /* Mount count */
__le16 s_max_mnt_count; /* Maximal mount count */ __le16 s_max_mnt_count; /* Maximal mount count */
__le16 s_state; /* File system state */ __le16 s_state; /* File system state */
__le16 s_errors; /* Behaviour when detecting errors */ __le16 s_errors; /* Behaviour when detecting errors */
__le64 s_lastcheck; /* time of last check */ __le64 s_lastcheck; /* time of last check */
__le32 s_checkinterval; /* max. time between checks */ /*80*/ __le32 s_checkinterval; /* max. time between checks */
__le32 s_creator_os; /* OS */ __le32 s_creator_os; /* OS */
__le16 s_def_resuid; /* Default uid for reserved blocks */ __le16 s_def_resuid; /* Default uid for reserved blocks */
__le16 s_def_resgid; /* Default gid for reserved blocks */ __le16 s_def_resgid; /* Default gid for reserved blocks */
__le32 s_first_ino; /* First non-reserved inode */ __le32 s_first_ino; /* First non-reserved inode */
__le16 s_inode_size; /* Size of an inode */ /*90*/ __le16 s_inode_size; /* Size of an inode */
__le16 s_dat_entry_size; /* Size of a dat entry */ __le16 s_dat_entry_size; /* Size of a dat entry */
__le16 s_checkpoint_size; /* Size of a checkpoint */ __le16 s_checkpoint_size; /* Size of a checkpoint */
__le16 s_segment_usage_size; /* Size of a segment usage */ __le16 s_segment_usage_size; /* Size of a segment usage */
__u8 s_uuid[16]; /* 128-bit uuid for volume */ /*98*/ __u8 s_uuid[16]; /* 128-bit uuid for volume */
char s_volume_name[80]; /* volume name */ /*A8*/ char s_volume_name[80]; /* volume name */
__le32 s_c_interval; /* Commit interval of segment */ /*F8*/ __le32 s_c_interval; /* Commit interval of segment */
__le32 s_c_block_max; /* Threshold of data amount for __le32 s_c_block_max; /* Threshold of data amount for
the segment construction */ the segment construction */
__u32 s_reserved[192]; /* padding to the end of the block */ /*100*/ __le64 s_feature_compat; /* Compatible feature set */
__le64 s_feature_compat_ro; /* Read-only compatible feature set */
__le64 s_feature_incompat; /* Incompatible feature set */
__u32 s_reserved[186]; /* padding to the end of the block */
}; };
/* /*
...@@ -227,6 +230,16 @@ struct nilfs_super_block { ...@@ -227,6 +230,16 @@ struct nilfs_super_block {
#define NILFS_CURRENT_REV 2 /* current major revision */ #define NILFS_CURRENT_REV 2 /* current major revision */
#define NILFS_MINOR_REV 0 /* minor revision */ #define NILFS_MINOR_REV 0 /* minor revision */
/*
* Feature set definitions
*
* If there is a bit set in the incompatible feature set that the kernel
* doesn't know about, it should refuse to mount the filesystem.
*/
#define NILFS_FEATURE_COMPAT_SUPP 0ULL
#define NILFS_FEATURE_COMPAT_RO_SUPP 0ULL
#define NILFS_FEATURE_INCOMPAT_SUPP 0ULL
/* /*
* Bytes count of super_block for CRC-calculation * Bytes count of super_block for CRC-calculation
*/ */
...@@ -273,6 +286,12 @@ struct nilfs_super_block { ...@@ -273,6 +286,12 @@ struct nilfs_super_block {
#define NILFS_NAME_LEN 255 #define NILFS_NAME_LEN 255
/*
* Block size limitations
*/
#define NILFS_MIN_BLOCK_SIZE 1024
#define NILFS_MAX_BLOCK_SIZE 65536
/* /*
* The new version of the directory entry. Since V0 structures are * The new version of the directory entry. Since V0 structures are
* stored in intel byte order, and the name_len field could never be * stored in intel byte order, and the name_len field could never be
...@@ -313,7 +332,25 @@ enum { ...@@ -313,7 +332,25 @@ enum {
#define NILFS_DIR_ROUND (NILFS_DIR_PAD - 1) #define NILFS_DIR_ROUND (NILFS_DIR_PAD - 1)
#define NILFS_DIR_REC_LEN(name_len) (((name_len) + 12 + NILFS_DIR_ROUND) & \ #define NILFS_DIR_REC_LEN(name_len) (((name_len) + 12 + NILFS_DIR_ROUND) & \
~NILFS_DIR_ROUND) ~NILFS_DIR_ROUND)
#define NILFS_MAX_REC_LEN ((1<<16)-1)
static inline unsigned nilfs_rec_len_from_disk(__le16 dlen)
{
unsigned len = le16_to_cpu(dlen);
if (len == NILFS_MAX_REC_LEN)
return 1 << 16;
return len;
}
static inline __le16 nilfs_rec_len_to_disk(unsigned len)
{
if (len == (1 << 16))
return cpu_to_le16(NILFS_MAX_REC_LEN);
else if (len > (1 << 16))
BUG();
return cpu_to_le16(len);
}
/** /**
* struct nilfs_finfo - file information * struct nilfs_finfo - file information
......
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