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
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
============
......
......@@ -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;
......
......@@ -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 *);
......
/*
* 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)
}
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;
}
......
......@@ -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 *);
......
This diff is collapsed.
......@@ -30,14 +30,6 @@
#include "btnode.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
* @bp_bh: buffer head of node block
......@@ -54,7 +46,7 @@ struct nilfs_btree_path {
union nilfs_bmap_ptr_req bp_oldreq;
union nilfs_bmap_ptr_req bp_newreq;
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 *);
};
......@@ -80,4 +72,6 @@ int nilfs_btree_convert_and_insert(struct nilfs_bmap *, __u64, __u64,
const __u64 *, const __u64 *, int);
void nilfs_btree_init_gc(struct nilfs_bmap *);
int nilfs_btree_broken_node_block(struct buffer_head *bh);
#endif /* _NILFS_BTREE_H */
......@@ -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) {
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))
goto Eshort;
......@@ -199,13 +199,10 @@ static void nilfs_check_page(struct page *page)
static struct page *nilfs_get_page(struct inode *dir, unsigned long n)
{
struct address_space *mapping = dir->i_mapping;
struct page *page = read_cache_page(mapping, n,
(filler_t *)mapping->a_ops->readpage, NULL);
struct page *page = read_mapping_page(mapping, n, NULL);
if (!IS_ERR(page)) {
wait_on_page_locked(page);
kmap(page);
if (!PageUptodate(page))
goto fail;
if (!PageChecked(page))
nilfs_check_page(page);
if (PageError(page))
......@@ -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)
{
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
......@@ -329,7 +327,7 @@ static int nilfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
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);
}
......@@ -444,7 +442,7 @@ void nilfs_set_link(struct inode *dir, struct nilfs_dir_entry *de,
struct page *page, struct inode *inode)
{
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;
int err;
......@@ -500,7 +498,7 @@ int nilfs_add_link(struct dentry *dentry, struct inode *inode)
/* We hit i_size */
name_len = 0;
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;
goto got_it;
}
......@@ -514,7 +512,7 @@ int nilfs_add_link(struct dentry *dentry, struct inode *inode)
if (nilfs_match(namelen, name, de))
goto out_unlock;
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)
goto got_it;
if (rec_len >= name_len + reclen)
......@@ -537,8 +535,8 @@ int nilfs_add_link(struct dentry *dentry, struct inode *inode)
struct nilfs_dir_entry *de1;
de1 = (struct nilfs_dir_entry *)((char *)de + name_len);
de1->rec_len = cpu_to_le16(rec_len - name_len);
de->rec_len = cpu_to_le16(name_len);
de1->rec_len = nilfs_rec_len_to_disk(rec_len - name_len);
de->rec_len = nilfs_rec_len_to_disk(name_len);
de = de1;
}
de->name_len = namelen;
......@@ -569,7 +567,8 @@ int nilfs_delete_entry(struct nilfs_dir_entry *dir, struct page *page)
struct inode *inode = mapping->host;
char *kaddr = page_address(page);
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 *de = (struct nilfs_dir_entry *)(kaddr + from);
int err;
......@@ -590,7 +589,7 @@ int nilfs_delete_entry(struct nilfs_dir_entry *dir, struct page *page)
err = nilfs_prepare_chunk(page, mapping, from, to);
BUG_ON(err);
if (pde)
pde->rec_len = cpu_to_le16(to - from);
pde->rec_len = nilfs_rec_len_to_disk(to - from);
dir->inode = 0;
nilfs_commit_chunk(page, mapping, from, to);
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
......@@ -624,14 +623,14 @@ int nilfs_make_empty(struct inode *inode, struct inode *parent)
memset(kaddr, 0, chunk_size);
de = (struct nilfs_dir_entry *)kaddr;
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);
de->inode = cpu_to_le64(inode->i_ino);
nilfs_set_de_type(de, inode);
de = (struct nilfs_dir_entry *)(kaddr + NILFS_DIR_REC_LEN(1));
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);
memcpy(de->name, "..\0", 4);
nilfs_set_de_type(de, inode);
......
This diff is collapsed.
......@@ -28,8 +28,6 @@
#include "bmap.h"
struct nilfs_direct;
/**
* struct nilfs_direct_node - direct node
* @dn_flags: flags
......@@ -40,15 +38,6 @@ struct nilfs_direct_node {
__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_KEY_MIN 0
#define NILFS_DIRECT_KEY_MAX (NILFS_DIRECT_NBLOCKS - 1)
......
......@@ -48,6 +48,8 @@
#include <linux/slab.h>
#include <linux/swap.h>
#include "nilfs.h"
#include "btree.h"
#include "btnode.h"
#include "page.h"
#include "mdt.h"
#include "dat.h"
......@@ -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,
__u64 vbn, struct buffer_head **out_bh)
{
int ret = nilfs_btnode_submit_block(&NILFS_I(inode)->i_btnode_cache,
vbn ? : pbn, pbn, out_bh);
int ret;
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) */
ret = 0;
return ret;
......@@ -164,10 +168,15 @@ int nilfs_gccache_wait_and_mark_dirty(struct buffer_head *bh)
if (buffer_dirty(bh))
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);
else
} else {
nilfs_mdt_mark_buffer_dirty(bh);
}
return 0;
}
......
......@@ -28,6 +28,7 @@
#include <linux/swap.h>
#include <linux/slab.h>
#include "nilfs.h"
#include "btnode.h"
#include "segment.h"
#include "page.h"
#include "mdt.h"
......
......@@ -32,7 +32,6 @@
#include "the_nilfs.h"
#include "sb.h"
#include "bmap.h"
#include "bmap_union.h"
/*
* nilfs inode data in memory
......@@ -41,7 +40,7 @@ struct nilfs_inode_info {
__u32 i_flags;
unsigned long i_state; /* Dynamic state flags */
struct nilfs_bmap *i_bmap;
union nilfs_bmap_union i_bmap_union;
struct nilfs_bmap i_bmap_data;
__u64 i_xattr; /* sector_t ??? */
__u32 i_dir_start_lookup;
__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)
static inline struct nilfs_inode_info *
NILFS_BMAP_I(const struct nilfs_bmap *bmap)
{
return container_of((union nilfs_bmap_union *)bmap,
struct nilfs_inode_info,
i_bmap_union);
return container_of(bmap, struct nilfs_inode_info, i_bmap_data);
}
static inline struct inode *NILFS_BTNC_I(struct address_space *btnc)
......@@ -106,6 +103,14 @@ enum {
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
*/
......@@ -270,7 +275,14 @@ extern struct nilfs_super_block *
nilfs_read_super_block(struct super_block *, u64, int, struct buffer_head **);
extern int nilfs_store_magic_and_option(struct super_block *,
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_cleanup_super(struct nilfs_sb_info *);
extern int nilfs_attach_checkpoint(struct nilfs_sb_info *, __u64);
extern void nilfs_detach_checkpoint(struct nilfs_sb_info *);
......
......@@ -37,7 +37,8 @@
#define NILFS_BUFFER_INHERENT_BITS \
((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 *
__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)
lock_buffer(bh);
clear_buffer_nilfs_volatile(bh);
clear_buffer_nilfs_checked(bh);
clear_buffer_dirty(bh);
if (nilfs_page_buffers_clean(page))
__nilfs_clear_page_dirty(page);
......@@ -480,6 +482,7 @@ void nilfs_clear_dirty_pages(struct address_space *mapping)
lock_buffer(bh);
clear_buffer_dirty(bh);
clear_buffer_nilfs_volatile(bh);
clear_buffer_nilfs_checked(bh);
clear_buffer_uptodate(bh);
clear_buffer_mapped(bh);
unlock_buffer(bh);
......
......@@ -34,11 +34,13 @@ enum {
BH_NILFS_Allocated = BH_PrivateStart,
BH_NILFS_Node,
BH_NILFS_Volatile,
BH_NILFS_Checked,
};
BUFFER_FNS(NILFS_Allocated, nilfs_allocated) /* nilfs private buffers */
BUFFER_FNS(NILFS_Node, nilfs_node) /* nilfs node buffers */
BUFFER_FNS(NILFS_Volatile, nilfs_volatile)
BUFFER_FNS(NILFS_Checked, nilfs_checked) /* buffer is verified */
void nilfs_mark_buffer_dirty(struct buffer_head *bh);
......
This diff is collapsed.
......@@ -54,17 +54,6 @@ struct nilfs_segsum_info {
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
* @sb_super: back pointer to a superblock struct
......@@ -141,6 +130,19 @@ int nilfs_segbuf_extend_payload(struct nilfs_segment_buffer *,
struct buffer_head **);
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
nilfs_segbuf_add_segsum_buffer(struct nilfs_segment_buffer *segbuf,
struct buffer_head *bh)
......
......@@ -1914,12 +1914,12 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci)
}
}
if (!NILFS_SEG_SIMPLEX(&segbuf->sb_sum)) {
if (NILFS_SEG_LOGBGN(&segbuf->sb_sum)) {
if (!nilfs_segbuf_simplex(segbuf)) {
if (segbuf->sb_sum.flags & NILFS_SS_LOGBGN) {
set_bit(NILFS_SC_UNCLOSED, &sci->sc_flags);
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);
}
}
......@@ -1951,7 +1951,6 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci)
if (update_sr) {
nilfs_set_last_segment(nilfs, segbuf->sb_pseg_start,
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_DIRTY, &sci->sc_flags);
......@@ -2082,7 +2081,7 @@ static int nilfs_segctor_do_construct(struct nilfs_sc_info *sci, int mode)
/* Avoid empty segment */
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);
goto out;
}
......@@ -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 the_nilfs *nilfs = sbi->s_nilfs;
struct nilfs_super_block **sbp;
int err = 0;
nilfs_segctor_accept(sci);
......@@ -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) &&
nilfs_discontinued(nilfs)) {
down_write(&nilfs->ns_sem);
err = nilfs_commit_super(
sbi, nilfs_altsb_need_update(nilfs));
err = -EIO;
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);
}
}
......
......@@ -234,13 +234,13 @@ extern int nilfs_attach_segment_constructor(struct nilfs_sb_info *);
extern void nilfs_detach_segment_constructor(struct nilfs_sb_info *);
/* 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);
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 *);
extern int nilfs_recover_logical_segments(struct the_nilfs *,
struct nilfs_sb_info *,
struct nilfs_recovery_info *);
extern int nilfs_salvage_orphan_logs(struct the_nilfs *,
struct nilfs_sb_info *,
struct nilfs_recovery_info *);
extern void nilfs_dispose_segment_list(struct list_head *);
#endif /* _NILFS_SEGMENT_H */
This diff is collapsed.
......@@ -38,6 +38,8 @@
static LIST_HEAD(nilfs_objects);
static DEFINE_SPINLOCK(nilfs_lock);
static int nilfs_valid_sb(struct nilfs_super_block *sbp);
void nilfs_set_last_segment(struct the_nilfs *nilfs,
sector_t start_blocknr, u64 seq, __u64 cno)
{
......@@ -45,6 +47,16 @@ void nilfs_set_last_segment(struct the_nilfs *nilfs,
nilfs->ns_last_pseg = start_blocknr;
nilfs->ns_last_seq = seq;
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);
}
......@@ -159,8 +171,7 @@ void put_nilfs(struct the_nilfs *nilfs)
kfree(nilfs);
}
static int nilfs_load_super_root(struct the_nilfs *nilfs,
struct nilfs_sb_info *sbi, sector_t sr_block)
static int nilfs_load_super_root(struct the_nilfs *nilfs, sector_t sr_block)
{
struct buffer_head *bh_sr;
struct nilfs_super_root *raw_sr;
......@@ -169,7 +180,7 @@ static int nilfs_load_super_root(struct the_nilfs *nilfs,
unsigned inode_size;
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))
return err;
......@@ -247,6 +258,37 @@ static void nilfs_clear_recovery_info(struct nilfs_recovery_info *ri)
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
* @nilfs: the_nilfs structure to be released
......@@ -285,13 +327,55 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)
nilfs_init_recovery_info(&ri);
err = nilfs_search_super_root(nilfs, sbi, &ri);
err = nilfs_search_super_root(nilfs, &ri);
if (unlikely(err)) {
printk(KERN_ERR "NILFS: error searching super root.\n");
goto failed;
struct nilfs_super_block **sbp = nilfs->ns_sbp;
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)) {
printk(KERN_ERR "NILFS: error loading super root.\n");
goto failed;
......@@ -301,11 +385,23 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)
goto skip_recovery;
if (s_flags & MS_RDONLY) {
__u64 features;
if (nilfs_test_opt(sbi, NORECOVERY)) {
printk(KERN_INFO "NILFS: norecovery option specified. "
"skipping roll-forward recovery\n");
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) {
printk(KERN_ERR "NILFS: write access "
"unavailable, cannot proceed.\n");
......@@ -320,14 +416,13 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)
goto failed_unload;
}
err = nilfs_recover_logical_segments(nilfs, sbi, &ri);
err = nilfs_salvage_orphan_logs(nilfs, sbi, &ri);
if (err)
goto failed_unload;
down_write(&nilfs->ns_sem);
nilfs->ns_mount_state |= NILFS_VALID_FS;
nilfs->ns_sbp[0]->s_state = cpu_to_le16(nilfs->ns_mount_state);
err = nilfs_commit_super(sbi, 1);
nilfs->ns_mount_state |= NILFS_VALID_FS; /* set "clean" flag */
err = nilfs_cleanup_super(sbi);
up_write(&nilfs->ns_sem);
if (err) {
......@@ -343,6 +438,10 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)
sbi->s_super->s_flags = s_flags;
return 0;
scan_error:
printk(KERN_ERR "NILFS: error searching super root.\n");
goto failed;
failed_unload:
nilfs_mdt_destroy(nilfs->ns_cpfile);
nilfs_mdt_destroy(nilfs->ns_sufile);
......@@ -515,8 +614,8 @@ static int nilfs_load_super_block(struct the_nilfs *nilfs,
nilfs_swap_super_block(nilfs);
}
nilfs->ns_sbwtime[0] = le64_to_cpu(sbp[0]->s_wtime);
nilfs->ns_sbwtime[1] = valid[!swp] ? le64_to_cpu(sbp[1]->s_wtime) : 0;
nilfs->ns_sbwcount = 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);
*sbpp = sbp[0];
return 0;
......@@ -557,6 +656,10 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
if (err)
goto out;
err = nilfs_check_feature_compatibility(sb, sbp);
if (err)
goto out;
blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size);
if (sb->s_blocksize != blocksize &&
!sb_set_blocksize(sb, blocksize)) {
......@@ -568,7 +671,7 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
goto out;
}
blocksize = sb_min_blocksize(sb, BLOCK_SIZE);
blocksize = sb_min_blocksize(sb, NILFS_MIN_BLOCK_SIZE);
if (!blocksize) {
printk(KERN_ERR "NILFS: unable to set blocksize\n");
err = -EINVAL;
......@@ -582,7 +685,18 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
if (err)
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);
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) {
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)
when reloading fails. */
}
nilfs->ns_blocksize_bits = sb->s_blocksize_bits;
nilfs->ns_blocksize = blocksize;
err = nilfs_store_disk_layout(nilfs, sbp);
if (err)
......@@ -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;
nilfs->ns_bdi = bdi ? : &default_backing_dev_info;
/* Finding last segment */
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_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;
err = nilfs_store_log_cursor(nilfs, sbp);
if (err)
goto failed_sbh;
}
/* Dummy values */
nilfs->ns_free_segments_count =
nilfs->ns_nsegments - (nilfs->ns_segnum + 1);
/* Initialize gcinode cache */
err = nilfs_init_gccache(nilfs);
......
......@@ -57,7 +57,8 @@ enum {
* @ns_current: back pointer to current mount
* @ns_sbh: buffer heads of on-disk super blocks
* @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_supers: list of nilfs super block structs
* @ns_seg_seq: segment sequence counter
......@@ -73,7 +74,7 @@ enum {
* @ns_last_seq: sequence value 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_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_dat: DAT file inode
* @ns_cpfile: checkpoint file inode
......@@ -82,6 +83,7 @@ enum {
* @ns_gc_inodes: dummy inodes to keep 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: block size
* @ns_nsegments: number of segments in filesystem
* @ns_blocks_per_segment: number of blocks per segment
* @ns_r_segments_percentage: reserved segments percentage
......@@ -119,7 +121,8 @@ struct the_nilfs {
*/
struct buffer_head *ns_sbh[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_mount_state;
......@@ -149,7 +152,7 @@ struct the_nilfs {
u64 ns_last_seq;
__u64 ns_last_cno;
u64 ns_prot_seq;
unsigned long ns_free_segments_count;
u64 ns_prev_seq;
struct rw_semaphore ns_segctor_sem;
......@@ -168,6 +171,7 @@ struct the_nilfs {
/* Disk layout information (static) */
unsigned int ns_blocksize_bits;
unsigned int ns_blocksize;
unsigned long ns_nsegments;
unsigned long ns_blocks_per_segment;
unsigned long ns_r_segments_percentage;
......@@ -203,20 +207,17 @@ THE_NILFS_FNS(SB_DIRTY, sb_dirty)
/* Minimum interval of periodical update of superblocks (in seconds) */
#define NILFS_SB_FREQ 10
#define NILFS_ALTSB_FREQ 60 /* spare superblock */
static inline int nilfs_sb_need_update(struct the_nilfs *nilfs)
{
u64 t = get_seconds();
return t < nilfs->ns_sbwtime[0] ||
t > nilfs->ns_sbwtime[0] + NILFS_SB_FREQ;
return t < nilfs->ns_sbwtime || t > nilfs->ns_sbwtime + 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();
struct nilfs_super_block **sbp = nilfs->ns_sbp;
return sbp[1] && t > nilfs->ns_sbwtime[1] + NILFS_ALTSB_FREQ;
int flip_bits = nilfs->ns_sbwcount & 0x0FL;
return (flip_bits != 0x08 && flip_bits != 0x0F);
}
void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64);
......
......@@ -160,7 +160,7 @@ struct nilfs_super_root {
* struct nilfs_super_block - structure of super block on disk
*/
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_magic; /* Magic signature */
......@@ -169,50 +169,53 @@ struct nilfs_super_block {
is excluded. */
__le16 s_flags; /* flags */
__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
blocksize =
1 << (s_log_block_size + 10) */
__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 */
__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 */
__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_free_blocks_count; /* Free blocks count */
/*50*/ __le64 s_free_blocks_count; /* Free blocks count */
__le64 s_ctime; /* Creation time (execution time of
newfs) */
__le64 s_mtime; /* Mount time */
/*60*/ __le64 s_mtime; /* Mount 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_state; /* File system state */
__le16 s_errors; /* Behaviour when detecting errors */
__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 */
__le16 s_def_resuid; /* Default uid for reserved blocks */
__le16 s_def_resgid; /* Default gid for reserved blocks */
__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_checkpoint_size; /* Size of a checkpoint */
__le16 s_segment_usage_size; /* Size of a segment usage */
__u8 s_uuid[16]; /* 128-bit uuid for volume */
char s_volume_name[80]; /* volume name */
/*98*/ __u8 s_uuid[16]; /* 128-bit uuid for volume */
/*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
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 {
#define NILFS_CURRENT_REV 2 /* current major 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
*/
......@@ -273,6 +286,12 @@ struct nilfs_super_block {
#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
* stored in intel byte order, and the name_len field could never be
......@@ -313,7 +332,25 @@ enum {
#define NILFS_DIR_ROUND (NILFS_DIR_PAD - 1)
#define NILFS_DIR_REC_LEN(name_len) (((name_len) + 12 + 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
......
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