Commit 9c7cb99a 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: (22 commits)
  nilfs2: support contiguous lookup of blocks
  nilfs2: add sync_page method to page caches of meta data
  nilfs2: use device's backing_dev_info for btree node caches
  nilfs2: return EBUSY against delete request on snapshot
  nilfs2: modify list of unsupported features in caveats
  nilfs2: enable sync_page method
  nilfs2: set bio unplug flag for the last bio in segment
  nilfs2: allow future expansion of metadata read out via get info ioctl
  NILFS2: Pagecache usage optimization on NILFS2
  nilfs2: remove nilfs_btree_operations from btree mapping
  nilfs2: remove nilfs_direct_operations from direct mapping
  nilfs2: remove bmap pointer operations
  nilfs2: remove useless b_low and b_high fields from nilfs_bmap struct
  nilfs2: remove pointless NULL check of bpop_commit_alloc_ptr function
  nilfs2: move get block functions in bmap.c into btree codes
  nilfs2: remove nilfs_bmap_delete_block
  nilfs2: remove nilfs_bmap_put_block
  nilfs2: remove header file for segment list operations
  nilfs2: eliminate removal list of segments
  nilfs2: add sufile function that can modify multiple segment usages
  ...
parents 0a8eba9b c3a7abf0
...@@ -39,9 +39,8 @@ Features which NILFS2 does not support yet: ...@@ -39,9 +39,8 @@ Features which NILFS2 does not support yet:
- extended attributes - extended attributes
- POSIX ACLs - POSIX ACLs
- quotas - quotas
- writable snapshots - fsck
- remote backup (CDP) - resize
- data integrity
- defragmentation - defragmentation
Mount options Mount options
......
This diff is collapsed.
...@@ -64,6 +64,8 @@ struct nilfs_bmap_stats { ...@@ -64,6 +64,8 @@ struct nilfs_bmap_stats {
*/ */
struct nilfs_bmap_operations { struct nilfs_bmap_operations {
int (*bop_lookup)(const struct nilfs_bmap *, __u64, int, __u64 *); int (*bop_lookup)(const struct nilfs_bmap *, __u64, int, __u64 *);
int (*bop_lookup_contig)(const struct nilfs_bmap *, __u64, __u64 *,
unsigned);
int (*bop_insert)(struct nilfs_bmap *, __u64, __u64); int (*bop_insert)(struct nilfs_bmap *, __u64, __u64);
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 *);
...@@ -86,34 +88,6 @@ struct nilfs_bmap_operations { ...@@ -86,34 +88,6 @@ struct nilfs_bmap_operations {
}; };
/**
* struct nilfs_bmap_ptr_operations - bmap ptr operation table
*/
struct nilfs_bmap_ptr_operations {
int (*bpop_prepare_alloc_ptr)(struct nilfs_bmap *,
union nilfs_bmap_ptr_req *);
void (*bpop_commit_alloc_ptr)(struct nilfs_bmap *,
union nilfs_bmap_ptr_req *);
void (*bpop_abort_alloc_ptr)(struct nilfs_bmap *,
union nilfs_bmap_ptr_req *);
int (*bpop_prepare_start_ptr)(struct nilfs_bmap *,
union nilfs_bmap_ptr_req *);
void (*bpop_commit_start_ptr)(struct nilfs_bmap *,
union nilfs_bmap_ptr_req *,
sector_t);
void (*bpop_abort_start_ptr)(struct nilfs_bmap *,
union nilfs_bmap_ptr_req *);
int (*bpop_prepare_end_ptr)(struct nilfs_bmap *,
union nilfs_bmap_ptr_req *);
void (*bpop_commit_end_ptr)(struct nilfs_bmap *,
union nilfs_bmap_ptr_req *);
void (*bpop_abort_end_ptr)(struct nilfs_bmap *,
union nilfs_bmap_ptr_req *);
int (*bpop_translate)(const struct nilfs_bmap *, __u64, __u64 *);
};
#define NILFS_BMAP_SIZE (NILFS_INODE_BMAP_SIZE * sizeof(__le64)) #define NILFS_BMAP_SIZE (NILFS_INODE_BMAP_SIZE * sizeof(__le64))
#define NILFS_BMAP_KEY_BIT (sizeof(unsigned long) * 8 /* CHAR_BIT */) #define NILFS_BMAP_KEY_BIT (sizeof(unsigned long) * 8 /* CHAR_BIT */)
#define NILFS_BMAP_NEW_PTR_INIT \ #define NILFS_BMAP_NEW_PTR_INIT \
...@@ -131,11 +105,9 @@ static inline int nilfs_bmap_is_new_ptr(unsigned long ptr) ...@@ -131,11 +105,9 @@ static inline int nilfs_bmap_is_new_ptr(unsigned long ptr)
* @b_sem: semaphore * @b_sem: semaphore
* @b_inode: owner of bmap * @b_inode: owner of bmap
* @b_ops: bmap operation table * @b_ops: bmap operation table
* @b_pops: bmap ptr operation table
* @b_low: low watermark of conversion
* @b_high: high watermark of conversion
* @b_last_allocated_key: last allocated key for data block * @b_last_allocated_key: last allocated key for data block
* @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_state: state * @b_state: state
*/ */
struct nilfs_bmap { struct nilfs_bmap {
...@@ -146,14 +118,22 @@ struct nilfs_bmap { ...@@ -146,14 +118,22 @@ struct nilfs_bmap {
struct rw_semaphore b_sem; struct rw_semaphore b_sem;
struct inode *b_inode; struct inode *b_inode;
const struct nilfs_bmap_operations *b_ops; const struct nilfs_bmap_operations *b_ops;
const struct nilfs_bmap_ptr_operations *b_pops;
__u64 b_low;
__u64 b_high;
__u64 b_last_allocated_key; __u64 b_last_allocated_key;
__u64 b_last_allocated_ptr; __u64 b_last_allocated_ptr;
int b_ptr_type;
int b_state; int b_state;
}; };
/* pointer type */
#define NILFS_BMAP_PTR_P 0 /* physical block number (i.e. LBN) */
#define NILFS_BMAP_PTR_VS 1 /* virtual block number (single
version) */
#define NILFS_BMAP_PTR_VM 2 /* virtual block number (has multiple
versions) */
#define NILFS_BMAP_PTR_U (-1) /* never perform pointer operations */
#define NILFS_BMAP_USE_VBN(bmap) ((bmap)->b_ptr_type > 0)
/* state */ /* state */
#define NILFS_BMAP_DIRTY 0x00000001 #define NILFS_BMAP_DIRTY 0x00000001
...@@ -162,6 +142,7 @@ int nilfs_bmap_test_and_clear_dirty(struct nilfs_bmap *); ...@@ -162,6 +142,7 @@ int nilfs_bmap_test_and_clear_dirty(struct nilfs_bmap *);
int nilfs_bmap_read(struct nilfs_bmap *, struct nilfs_inode *); int nilfs_bmap_read(struct nilfs_bmap *, struct nilfs_inode *);
void nilfs_bmap_write(struct nilfs_bmap *, struct nilfs_inode *); void nilfs_bmap_write(struct nilfs_bmap *, struct nilfs_inode *);
int nilfs_bmap_lookup(struct nilfs_bmap *, unsigned long, unsigned long *); int nilfs_bmap_lookup(struct nilfs_bmap *, unsigned long, unsigned long *);
int nilfs_bmap_lookup_contig(struct nilfs_bmap *, __u64, __u64 *, unsigned);
int nilfs_bmap_insert(struct nilfs_bmap *, unsigned long, unsigned long); int nilfs_bmap_insert(struct nilfs_bmap *, unsigned long, unsigned long);
int nilfs_bmap_delete(struct nilfs_bmap *, unsigned long); int nilfs_bmap_delete(struct nilfs_bmap *, unsigned long);
int nilfs_bmap_last_key(struct nilfs_bmap *, unsigned long *); int nilfs_bmap_last_key(struct nilfs_bmap *, unsigned long *);
...@@ -182,7 +163,67 @@ void nilfs_bmap_commit_gcdat(struct nilfs_bmap *, struct nilfs_bmap *); ...@@ -182,7 +163,67 @@ void nilfs_bmap_commit_gcdat(struct nilfs_bmap *, struct nilfs_bmap *);
/* /*
* Internal use only * Internal use only
*/ */
struct inode *nilfs_bmap_get_dat(const struct nilfs_bmap *);
int nilfs_bmap_prepare_alloc_v(struct nilfs_bmap *,
union nilfs_bmap_ptr_req *);
void nilfs_bmap_commit_alloc_v(struct nilfs_bmap *,
union nilfs_bmap_ptr_req *);
void nilfs_bmap_abort_alloc_v(struct nilfs_bmap *,
union nilfs_bmap_ptr_req *);
static inline int nilfs_bmap_prepare_alloc_ptr(struct nilfs_bmap *bmap,
union nilfs_bmap_ptr_req *req)
{
if (NILFS_BMAP_USE_VBN(bmap))
return nilfs_bmap_prepare_alloc_v(bmap, req);
/* ignore target ptr */
req->bpr_ptr = bmap->b_last_allocated_ptr++;
return 0;
}
static inline void nilfs_bmap_commit_alloc_ptr(struct nilfs_bmap *bmap,
union nilfs_bmap_ptr_req *req)
{
if (NILFS_BMAP_USE_VBN(bmap))
nilfs_bmap_commit_alloc_v(bmap, req);
}
static inline void nilfs_bmap_abort_alloc_ptr(struct nilfs_bmap *bmap,
union nilfs_bmap_ptr_req *req)
{
if (NILFS_BMAP_USE_VBN(bmap))
nilfs_bmap_abort_alloc_v(bmap, req);
else
bmap->b_last_allocated_ptr--;
}
int nilfs_bmap_prepare_end_v(struct nilfs_bmap *, union nilfs_bmap_ptr_req *);
void nilfs_bmap_commit_end_v(struct nilfs_bmap *, union nilfs_bmap_ptr_req *);
void nilfs_bmap_abort_end_v(struct nilfs_bmap *, union nilfs_bmap_ptr_req *);
static inline int nilfs_bmap_prepare_end_ptr(struct nilfs_bmap *bmap,
union nilfs_bmap_ptr_req *req)
{
return NILFS_BMAP_USE_VBN(bmap) ?
nilfs_bmap_prepare_end_v(bmap, req) : 0;
}
static inline void nilfs_bmap_commit_end_ptr(struct nilfs_bmap *bmap,
union nilfs_bmap_ptr_req *req)
{
if (NILFS_BMAP_USE_VBN(bmap))
nilfs_bmap_commit_end_v(bmap, req);
}
static inline void nilfs_bmap_abort_end_ptr(struct nilfs_bmap *bmap,
union nilfs_bmap_ptr_req *req)
{
if (NILFS_BMAP_USE_VBN(bmap))
nilfs_bmap_abort_end_v(bmap, req);
}
int nilfs_bmap_start_v(struct nilfs_bmap *, union nilfs_bmap_ptr_req *,
sector_t);
int nilfs_bmap_move_v(const struct nilfs_bmap *, __u64, sector_t); int nilfs_bmap_move_v(const struct nilfs_bmap *, __u64, sector_t);
int nilfs_bmap_mark_dirty(const struct nilfs_bmap *, __u64); int nilfs_bmap_mark_dirty(const struct nilfs_bmap *, __u64);
...@@ -193,28 +234,20 @@ __u64 nilfs_bmap_data_get_key(const struct nilfs_bmap *, ...@@ -193,28 +234,20 @@ __u64 nilfs_bmap_data_get_key(const struct nilfs_bmap *,
__u64 nilfs_bmap_find_target_seq(const struct nilfs_bmap *, __u64); __u64 nilfs_bmap_find_target_seq(const struct nilfs_bmap *, __u64);
__u64 nilfs_bmap_find_target_in_group(const struct nilfs_bmap *); __u64 nilfs_bmap_find_target_in_group(const struct nilfs_bmap *);
int nilfs_bmap_prepare_update(struct nilfs_bmap *, int nilfs_bmap_prepare_update_v(struct nilfs_bmap *,
union nilfs_bmap_ptr_req *, union nilfs_bmap_ptr_req *,
union nilfs_bmap_ptr_req *); union nilfs_bmap_ptr_req *);
void nilfs_bmap_commit_update(struct nilfs_bmap *, void nilfs_bmap_commit_update_v(struct nilfs_bmap *,
union nilfs_bmap_ptr_req *, union nilfs_bmap_ptr_req *,
union nilfs_bmap_ptr_req *); union nilfs_bmap_ptr_req *);
void nilfs_bmap_abort_update(struct nilfs_bmap *, void nilfs_bmap_abort_update_v(struct nilfs_bmap *,
union nilfs_bmap_ptr_req *, union nilfs_bmap_ptr_req *,
union nilfs_bmap_ptr_req *); union nilfs_bmap_ptr_req *);
void nilfs_bmap_add_blocks(const struct nilfs_bmap *, int); void nilfs_bmap_add_blocks(const struct nilfs_bmap *, int);
void nilfs_bmap_sub_blocks(const struct nilfs_bmap *, int); void nilfs_bmap_sub_blocks(const struct nilfs_bmap *, int);
int nilfs_bmap_get_block(const struct nilfs_bmap *, __u64,
struct buffer_head **);
void nilfs_bmap_put_block(const struct nilfs_bmap *, struct buffer_head *);
int nilfs_bmap_get_new_block(const struct nilfs_bmap *, __u64,
struct buffer_head **);
void nilfs_bmap_delete_block(const struct nilfs_bmap *, struct buffer_head *);
/* Assume that bmap semaphore is locked. */ /* Assume that bmap semaphore is locked. */
static inline int nilfs_bmap_dirty(const struct nilfs_bmap *bmap) static inline int nilfs_bmap_dirty(const struct nilfs_bmap *bmap)
{ {
......
...@@ -46,15 +46,18 @@ void nilfs_btnode_cache_init_once(struct address_space *btnc) ...@@ -46,15 +46,18 @@ void nilfs_btnode_cache_init_once(struct address_space *btnc)
INIT_LIST_HEAD(&btnc->i_mmap_nonlinear); INIT_LIST_HEAD(&btnc->i_mmap_nonlinear);
} }
static struct address_space_operations def_btnode_aops; static struct address_space_operations def_btnode_aops = {
.sync_page = block_sync_page,
};
void nilfs_btnode_cache_init(struct address_space *btnc) void nilfs_btnode_cache_init(struct address_space *btnc,
struct backing_dev_info *bdi)
{ {
btnc->host = NULL; /* can safely set to host inode ? */ btnc->host = NULL; /* can safely set to host inode ? */
btnc->flags = 0; btnc->flags = 0;
mapping_set_gfp_mask(btnc, GFP_NOFS); mapping_set_gfp_mask(btnc, GFP_NOFS);
btnc->assoc_mapping = NULL; btnc->assoc_mapping = NULL;
btnc->backing_dev_info = &default_backing_dev_info; btnc->backing_dev_info = bdi;
btnc->a_ops = &def_btnode_aops; btnc->a_ops = &def_btnode_aops;
} }
......
...@@ -38,7 +38,7 @@ struct nilfs_btnode_chkey_ctxt { ...@@ -38,7 +38,7 @@ struct nilfs_btnode_chkey_ctxt {
}; };
void nilfs_btnode_cache_init_once(struct address_space *); void nilfs_btnode_cache_init_once(struct address_space *);
void nilfs_btnode_cache_init(struct address_space *); 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 *);
int nilfs_btnode_submit_block(struct address_space *, __u64, sector_t, int nilfs_btnode_submit_block(struct address_space *, __u64, sector_t,
struct buffer_head **, int); struct buffer_head **, int);
......
This diff is collapsed.
...@@ -33,28 +33,6 @@ ...@@ -33,28 +33,6 @@
struct nilfs_btree; struct nilfs_btree;
struct nilfs_btree_path; struct nilfs_btree_path;
/**
* struct nilfs_btree_operations - B-tree operation table
*/
struct nilfs_btree_operations {
__u64 (*btop_find_target)(const struct nilfs_btree *,
const struct nilfs_btree_path *, __u64);
void (*btop_set_target)(struct nilfs_btree *, __u64, __u64);
struct the_nilfs *(*btop_get_nilfs)(struct nilfs_btree *);
int (*btop_propagate)(struct nilfs_btree *,
struct nilfs_btree_path *,
int,
struct buffer_head *);
int (*btop_assign)(struct nilfs_btree *,
struct nilfs_btree_path *,
int,
struct buffer_head **,
sector_t,
union nilfs_binfo *);
};
/** /**
* struct nilfs_btree_node - B-tree node * struct nilfs_btree_node - B-tree node
* @bn_flags: flags * @bn_flags: flags
...@@ -80,13 +58,9 @@ struct nilfs_btree_node { ...@@ -80,13 +58,9 @@ struct nilfs_btree_node {
/** /**
* struct nilfs_btree - B-tree structure * struct nilfs_btree - B-tree structure
* @bt_bmap: bmap base structure * @bt_bmap: bmap base structure
* @bt_ops: B-tree operation table
*/ */
struct nilfs_btree { struct nilfs_btree {
struct nilfs_bmap bt_bmap; struct nilfs_bmap bt_bmap;
/* B-tree-specific members */
const struct nilfs_btree_operations *bt_ops;
}; };
...@@ -108,10 +82,9 @@ struct nilfs_btree { ...@@ -108,10 +82,9 @@ struct nilfs_btree {
int nilfs_btree_path_cache_init(void); int nilfs_btree_path_cache_init(void);
void nilfs_btree_path_cache_destroy(void); void nilfs_btree_path_cache_destroy(void);
int nilfs_btree_init(struct nilfs_bmap *, __u64, __u64); int nilfs_btree_init(struct nilfs_bmap *);
int nilfs_btree_convert_and_insert(struct nilfs_bmap *, __u64, __u64, int nilfs_btree_convert_and_insert(struct nilfs_bmap *, __u64, __u64,
const __u64 *, const __u64 *, const __u64 *, const __u64 *, int);
int, __u64, __u64);
void nilfs_btree_init_gc(struct nilfs_bmap *); void nilfs_btree_init_gc(struct nilfs_bmap *);
#endif /* _NILFS_BTREE_H */ #endif /* _NILFS_BTREE_H */
...@@ -295,10 +295,6 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile, ...@@ -295,10 +295,6 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile,
return -EINVAL; return -EINVAL;
} }
/* cannot delete the latest checkpoint */
if (start == nilfs_mdt_cno(cpfile) - 1)
return -EPERM;
down_write(&NILFS_MDT(cpfile)->mi_sem); down_write(&NILFS_MDT(cpfile)->mi_sem);
ret = nilfs_cpfile_get_header_block(cpfile, &header_bh); ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);
...@@ -384,9 +380,10 @@ static void nilfs_cpfile_checkpoint_to_cpinfo(struct inode *cpfile, ...@@ -384,9 +380,10 @@ static void nilfs_cpfile_checkpoint_to_cpinfo(struct inode *cpfile,
} }
static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop, static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop,
struct nilfs_cpinfo *ci, size_t nci) void *buf, unsigned cisz, size_t nci)
{ {
struct nilfs_checkpoint *cp; struct nilfs_checkpoint *cp;
struct nilfs_cpinfo *ci = buf;
struct buffer_head *bh; struct buffer_head *bh;
size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size; size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size;
__u64 cur_cno = nilfs_mdt_cno(cpfile), cno = *cnop; __u64 cur_cno = nilfs_mdt_cno(cpfile), cno = *cnop;
...@@ -410,17 +407,22 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop, ...@@ -410,17 +407,22 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop,
kaddr = kmap_atomic(bh->b_page, KM_USER0); kaddr = kmap_atomic(bh->b_page, KM_USER0);
cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr); cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr);
for (i = 0; i < ncps && n < nci; i++, cp = (void *)cp + cpsz) { for (i = 0; i < ncps && n < nci; i++, cp = (void *)cp + cpsz) {
if (!nilfs_checkpoint_invalid(cp)) if (!nilfs_checkpoint_invalid(cp)) {
nilfs_cpfile_checkpoint_to_cpinfo( nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp,
cpfile, cp, &ci[n++]); ci);
ci = (void *)ci + cisz;
n++;
}
} }
kunmap_atomic(kaddr, KM_USER0); kunmap_atomic(kaddr, KM_USER0);
brelse(bh); brelse(bh);
} }
ret = n; ret = n;
if (n > 0) if (n > 0) {
*cnop = ci[n - 1].ci_cno + 1; ci = (void *)ci - cisz;
*cnop = ci->ci_cno + 1;
}
out: out:
up_read(&NILFS_MDT(cpfile)->mi_sem); up_read(&NILFS_MDT(cpfile)->mi_sem);
...@@ -428,11 +430,12 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop, ...@@ -428,11 +430,12 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop,
} }
static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop, static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop,
struct nilfs_cpinfo *ci, size_t nci) void *buf, unsigned cisz, size_t nci)
{ {
struct buffer_head *bh; struct buffer_head *bh;
struct nilfs_cpfile_header *header; struct nilfs_cpfile_header *header;
struct nilfs_checkpoint *cp; struct nilfs_checkpoint *cp;
struct nilfs_cpinfo *ci = buf;
__u64 curr = *cnop, next; __u64 curr = *cnop, next;
unsigned long curr_blkoff, next_blkoff; unsigned long curr_blkoff, next_blkoff;
void *kaddr; void *kaddr;
...@@ -472,7 +475,9 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop, ...@@ -472,7 +475,9 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop,
if (unlikely(nilfs_checkpoint_invalid(cp) || if (unlikely(nilfs_checkpoint_invalid(cp) ||
!nilfs_checkpoint_snapshot(cp))) !nilfs_checkpoint_snapshot(cp)))
break; break;
nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, &ci[n++]); nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, ci);
ci = (void *)ci + cisz;
n++;
next = le64_to_cpu(cp->cp_snapshot_list.ssl_next); next = le64_to_cpu(cp->cp_snapshot_list.ssl_next);
if (next == 0) if (next == 0)
break; /* reach end of the snapshot list */ break; /* reach end of the snapshot list */
...@@ -511,13 +516,13 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop, ...@@ -511,13 +516,13 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop,
*/ */
ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, __u64 *cnop, int mode, ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, __u64 *cnop, int mode,
struct nilfs_cpinfo *ci, size_t nci) void *buf, unsigned cisz, size_t nci)
{ {
switch (mode) { switch (mode) {
case NILFS_CHECKPOINT: case NILFS_CHECKPOINT:
return nilfs_cpfile_do_get_cpinfo(cpfile, cnop, ci, nci); return nilfs_cpfile_do_get_cpinfo(cpfile, cnop, buf, cisz, nci);
case NILFS_SNAPSHOT: case NILFS_SNAPSHOT:
return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, ci, nci); return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, buf, cisz, nci);
default: default:
return -EINVAL; return -EINVAL;
} }
...@@ -533,20 +538,14 @@ int nilfs_cpfile_delete_checkpoint(struct inode *cpfile, __u64 cno) ...@@ -533,20 +538,14 @@ int nilfs_cpfile_delete_checkpoint(struct inode *cpfile, __u64 cno)
struct nilfs_cpinfo ci; struct nilfs_cpinfo ci;
__u64 tcno = cno; __u64 tcno = cno;
ssize_t nci; ssize_t nci;
int ret;
nci = nilfs_cpfile_do_get_cpinfo(cpfile, &tcno, &ci, 1); nci = nilfs_cpfile_do_get_cpinfo(cpfile, &tcno, &ci, sizeof(ci), 1);
if (nci < 0) if (nci < 0)
return nci; return nci;
else if (nci == 0 || ci.ci_cno != cno) else if (nci == 0 || ci.ci_cno != cno)
return -ENOENT; return -ENOENT;
else if (nilfs_cpinfo_snapshot(&ci))
/* cannot delete the latest checkpoint nor snapshots */ return -EBUSY;
ret = nilfs_cpinfo_snapshot(&ci);
if (ret < 0)
return ret;
else if (ret > 0 || cno == nilfs_mdt_cno(cpfile) - 1)
return -EPERM;
return nilfs_cpfile_delete_checkpoints(cpfile, cno, cno + 1); return nilfs_cpfile_delete_checkpoints(cpfile, cno, cno + 1);
} }
......
...@@ -39,7 +39,7 @@ int nilfs_cpfile_delete_checkpoint(struct inode *, __u64); ...@@ -39,7 +39,7 @@ int nilfs_cpfile_delete_checkpoint(struct inode *, __u64);
int nilfs_cpfile_change_cpmode(struct inode *, __u64, int); int nilfs_cpfile_change_cpmode(struct inode *, __u64, int);
int nilfs_cpfile_is_snapshot(struct inode *, __u64); int nilfs_cpfile_is_snapshot(struct inode *, __u64);
int nilfs_cpfile_get_stat(struct inode *, struct nilfs_cpstat *); int nilfs_cpfile_get_stat(struct inode *, struct nilfs_cpstat *);
ssize_t nilfs_cpfile_get_cpinfo(struct inode *, __u64 *, int, ssize_t nilfs_cpfile_get_cpinfo(struct inode *, __u64 *, int, void *, unsigned,
struct nilfs_cpinfo *, size_t); size_t);
#endif /* _NILFS_CPFILE_H */ #endif /* _NILFS_CPFILE_H */
...@@ -92,21 +92,6 @@ void nilfs_dat_abort_alloc(struct inode *dat, struct nilfs_palloc_req *req) ...@@ -92,21 +92,6 @@ void nilfs_dat_abort_alloc(struct inode *dat, struct nilfs_palloc_req *req)
nilfs_palloc_abort_alloc_entry(dat, req); nilfs_palloc_abort_alloc_entry(dat, req);
} }
int nilfs_dat_prepare_free(struct inode *dat, struct nilfs_palloc_req *req)
{
int ret;
ret = nilfs_palloc_prepare_free_entry(dat, req);
if (ret < 0)
return ret;
ret = nilfs_dat_prepare_entry(dat, req, 0);
if (ret < 0) {
nilfs_palloc_abort_free_entry(dat, req);
return ret;
}
return 0;
}
void nilfs_dat_commit_free(struct inode *dat, struct nilfs_palloc_req *req) void nilfs_dat_commit_free(struct inode *dat, struct nilfs_palloc_req *req)
{ {
struct nilfs_dat_entry *entry; struct nilfs_dat_entry *entry;
...@@ -391,36 +376,37 @@ int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp) ...@@ -391,36 +376,37 @@ int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp)
return ret; return ret;
} }
ssize_t nilfs_dat_get_vinfo(struct inode *dat, struct nilfs_vinfo *vinfo, ssize_t nilfs_dat_get_vinfo(struct inode *dat, void *buf, unsigned visz,
size_t nvi) size_t nvi)
{ {
struct buffer_head *entry_bh; struct buffer_head *entry_bh;
struct nilfs_dat_entry *entry; struct nilfs_dat_entry *entry;
struct nilfs_vinfo *vinfo = buf;
__u64 first, last; __u64 first, last;
void *kaddr; void *kaddr;
unsigned long entries_per_block = NILFS_MDT(dat)->mi_entries_per_block; unsigned long entries_per_block = NILFS_MDT(dat)->mi_entries_per_block;
int i, j, n, ret; int i, j, n, ret;
for (i = 0; i < nvi; i += n) { for (i = 0; i < nvi; i += n) {
ret = nilfs_palloc_get_entry_block(dat, vinfo[i].vi_vblocknr, ret = nilfs_palloc_get_entry_block(dat, vinfo->vi_vblocknr,
0, &entry_bh); 0, &entry_bh);
if (ret < 0) if (ret < 0)
return ret; return ret;
kaddr = kmap_atomic(entry_bh->b_page, KM_USER0); kaddr = kmap_atomic(entry_bh->b_page, KM_USER0);
/* last virtual block number in this block */ /* last virtual block number in this block */
first = vinfo[i].vi_vblocknr; first = vinfo->vi_vblocknr;
do_div(first, entries_per_block); do_div(first, entries_per_block);
first *= entries_per_block; first *= entries_per_block;
last = first + entries_per_block - 1; last = first + entries_per_block - 1;
for (j = i, n = 0; for (j = i, n = 0;
j < nvi && vinfo[j].vi_vblocknr >= first && j < nvi && vinfo->vi_vblocknr >= first &&
vinfo[j].vi_vblocknr <= last; vinfo->vi_vblocknr <= last;
j++, n++) { j++, n++, vinfo = (void *)vinfo + visz) {
entry = nilfs_palloc_block_get_entry( entry = nilfs_palloc_block_get_entry(
dat, vinfo[j].vi_vblocknr, entry_bh, kaddr); dat, vinfo->vi_vblocknr, entry_bh, kaddr);
vinfo[j].vi_start = le64_to_cpu(entry->de_start); vinfo->vi_start = le64_to_cpu(entry->de_start);
vinfo[j].vi_end = le64_to_cpu(entry->de_end); vinfo->vi_end = le64_to_cpu(entry->de_end);
vinfo[j].vi_blocknr = le64_to_cpu(entry->de_blocknr); vinfo->vi_blocknr = le64_to_cpu(entry->de_blocknr);
} }
kunmap_atomic(kaddr, KM_USER0); kunmap_atomic(kaddr, KM_USER0);
brelse(entry_bh); brelse(entry_bh);
......
...@@ -47,6 +47,6 @@ void nilfs_dat_abort_end(struct inode *, struct nilfs_palloc_req *); ...@@ -47,6 +47,6 @@ void nilfs_dat_abort_end(struct inode *, struct nilfs_palloc_req *);
int nilfs_dat_mark_dirty(struct inode *, __u64); int nilfs_dat_mark_dirty(struct inode *, __u64);
int nilfs_dat_freev(struct inode *, __u64 *, size_t); int nilfs_dat_freev(struct inode *, __u64 *, size_t);
int nilfs_dat_move(struct inode *, __u64, sector_t); int nilfs_dat_move(struct inode *, __u64, sector_t);
ssize_t nilfs_dat_get_vinfo(struct inode *, struct nilfs_vinfo *, size_t); ssize_t nilfs_dat_get_vinfo(struct inode *, void *, unsigned, size_t);
#endif /* _NILFS_DAT_H */ #endif /* _NILFS_DAT_H */
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "page.h" #include "page.h"
#include "direct.h" #include "direct.h"
#include "alloc.h" #include "alloc.h"
#include "dat.h"
static inline __le64 *nilfs_direct_dptrs(const struct nilfs_direct *direct) static inline __le64 *nilfs_direct_dptrs(const struct nilfs_direct *direct)
{ {
...@@ -62,6 +63,47 @@ static int nilfs_direct_lookup(const struct nilfs_bmap *bmap, ...@@ -62,6 +63,47 @@ static int nilfs_direct_lookup(const struct nilfs_bmap *bmap,
return 0; return 0;
} }
static int nilfs_direct_lookup_contig(const struct nilfs_bmap *bmap,
__u64 key, __u64 *ptrp,
unsigned maxblocks)
{
struct nilfs_direct *direct = (struct nilfs_direct *)bmap;
struct inode *dat = NULL;
__u64 ptr, ptr2;
sector_t blocknr;
int ret, cnt;
if (key > NILFS_DIRECT_KEY_MAX ||
(ptr = nilfs_direct_get_ptr(direct, key)) ==
NILFS_BMAP_INVALID_PTR)
return -ENOENT;
if (NILFS_BMAP_USE_VBN(bmap)) {
dat = nilfs_bmap_get_dat(bmap);
ret = nilfs_dat_translate(dat, ptr, &blocknr);
if (ret < 0)
return ret;
ptr = blocknr;
}
maxblocks = min_t(unsigned, maxblocks, NILFS_DIRECT_KEY_MAX - key + 1);
for (cnt = 1; cnt < maxblocks &&
(ptr2 = nilfs_direct_get_ptr(direct, key + cnt)) !=
NILFS_BMAP_INVALID_PTR;
cnt++) {
if (dat) {
ret = nilfs_dat_translate(dat, ptr2, &blocknr);
if (ret < 0)
return ret;
ptr2 = blocknr;
}
if (ptr2 != ptr + cnt)
break;
}
*ptrp = ptr;
return cnt;
}
static __u64 static __u64
nilfs_direct_find_target_v(const struct nilfs_direct *direct, __u64 key) nilfs_direct_find_target_v(const struct nilfs_direct *direct, __u64 key)
{ {
...@@ -90,10 +132,9 @@ static int nilfs_direct_prepare_insert(struct nilfs_direct *direct, ...@@ -90,10 +132,9 @@ static int nilfs_direct_prepare_insert(struct nilfs_direct *direct,
{ {
int ret; int ret;
if (direct->d_ops->dop_find_target != NULL) if (NILFS_BMAP_USE_VBN(&direct->d_bmap))
req->bpr_ptr = direct->d_ops->dop_find_target(direct, key); req->bpr_ptr = nilfs_direct_find_target_v(direct, key);
ret = direct->d_bmap.b_pops->bpop_prepare_alloc_ptr(&direct->d_bmap, ret = nilfs_bmap_prepare_alloc_ptr(&direct->d_bmap, req);
req);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -111,16 +152,14 @@ static void nilfs_direct_commit_insert(struct nilfs_direct *direct, ...@@ -111,16 +152,14 @@ static void nilfs_direct_commit_insert(struct nilfs_direct *direct,
bh = (struct buffer_head *)((unsigned long)ptr); bh = (struct buffer_head *)((unsigned long)ptr);
set_buffer_nilfs_volatile(bh); set_buffer_nilfs_volatile(bh);
if (direct->d_bmap.b_pops->bpop_commit_alloc_ptr != NULL) nilfs_bmap_commit_alloc_ptr(&direct->d_bmap, req);
direct->d_bmap.b_pops->bpop_commit_alloc_ptr(
&direct->d_bmap, req);
nilfs_direct_set_ptr(direct, key, req->bpr_ptr); nilfs_direct_set_ptr(direct, key, req->bpr_ptr);
if (!nilfs_bmap_dirty(&direct->d_bmap)) if (!nilfs_bmap_dirty(&direct->d_bmap))
nilfs_bmap_set_dirty(&direct->d_bmap); nilfs_bmap_set_dirty(&direct->d_bmap);
if (direct->d_ops->dop_set_target != NULL) if (NILFS_BMAP_USE_VBN(&direct->d_bmap))
direct->d_ops->dop_set_target(direct, key, req->bpr_ptr); nilfs_direct_set_target_v(direct, key, req->bpr_ptr);
} }
static int nilfs_direct_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr) static int nilfs_direct_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr)
...@@ -152,25 +191,18 @@ static int nilfs_direct_prepare_delete(struct nilfs_direct *direct, ...@@ -152,25 +191,18 @@ static int nilfs_direct_prepare_delete(struct nilfs_direct *direct,
{ {
int ret; int ret;
if (direct->d_bmap.b_pops->bpop_prepare_end_ptr != NULL) { req->bpr_ptr = nilfs_direct_get_ptr(direct, key);
req->bpr_ptr = nilfs_direct_get_ptr(direct, key); ret = nilfs_bmap_prepare_end_ptr(&direct->d_bmap, req);
ret = direct->d_bmap.b_pops->bpop_prepare_end_ptr( if (!ret)
&direct->d_bmap, req); stats->bs_nblocks = 1;
if (ret < 0) return ret;
return ret;
}
stats->bs_nblocks = 1;
return 0;
} }
static void nilfs_direct_commit_delete(struct nilfs_direct *direct, static void nilfs_direct_commit_delete(struct nilfs_direct *direct,
union nilfs_bmap_ptr_req *req, union nilfs_bmap_ptr_req *req,
__u64 key) __u64 key)
{ {
if (direct->d_bmap.b_pops->bpop_commit_end_ptr != NULL) nilfs_bmap_commit_end_ptr(&direct->d_bmap, req);
direct->d_bmap.b_pops->bpop_commit_end_ptr(
&direct->d_bmap, req);
nilfs_direct_set_ptr(direct, key, NILFS_BMAP_INVALID_PTR); nilfs_direct_set_ptr(direct, key, NILFS_BMAP_INVALID_PTR);
} }
...@@ -244,8 +276,7 @@ static int nilfs_direct_gather_data(struct nilfs_bmap *bmap, ...@@ -244,8 +276,7 @@ static int nilfs_direct_gather_data(struct nilfs_bmap *bmap,
} }
int nilfs_direct_delete_and_convert(struct nilfs_bmap *bmap, int nilfs_direct_delete_and_convert(struct nilfs_bmap *bmap,
__u64 key, __u64 *keys, __u64 *ptrs, __u64 key, __u64 *keys, __u64 *ptrs, int n)
int n, __u64 low, __u64 high)
{ {
struct nilfs_direct *direct; struct nilfs_direct *direct;
__le64 *dptrs; __le64 *dptrs;
...@@ -275,8 +306,7 @@ int nilfs_direct_delete_and_convert(struct nilfs_bmap *bmap, ...@@ -275,8 +306,7 @@ int nilfs_direct_delete_and_convert(struct nilfs_bmap *bmap,
dptrs[i] = NILFS_BMAP_INVALID_PTR; dptrs[i] = NILFS_BMAP_INVALID_PTR;
} }
nilfs_direct_init(bmap, low, high); nilfs_direct_init(bmap);
return 0; return 0;
} }
...@@ -293,11 +323,11 @@ static int nilfs_direct_propagate_v(struct nilfs_direct *direct, ...@@ -293,11 +323,11 @@ static int nilfs_direct_propagate_v(struct nilfs_direct *direct,
if (!buffer_nilfs_volatile(bh)) { if (!buffer_nilfs_volatile(bh)) {
oldreq.bpr_ptr = ptr; oldreq.bpr_ptr = ptr;
newreq.bpr_ptr = ptr; newreq.bpr_ptr = ptr;
ret = nilfs_bmap_prepare_update(&direct->d_bmap, &oldreq, ret = nilfs_bmap_prepare_update_v(&direct->d_bmap, &oldreq,
&newreq); &newreq);
if (ret < 0) if (ret < 0)
return ret; return ret;
nilfs_bmap_commit_update(&direct->d_bmap, &oldreq, &newreq); nilfs_bmap_commit_update_v(&direct->d_bmap, &oldreq, &newreq);
set_buffer_nilfs_volatile(bh); set_buffer_nilfs_volatile(bh);
nilfs_direct_set_ptr(direct, key, newreq.bpr_ptr); nilfs_direct_set_ptr(direct, key, newreq.bpr_ptr);
} else } else
...@@ -309,12 +339,10 @@ static int nilfs_direct_propagate_v(struct nilfs_direct *direct, ...@@ -309,12 +339,10 @@ static int nilfs_direct_propagate_v(struct nilfs_direct *direct,
static int nilfs_direct_propagate(const struct nilfs_bmap *bmap, static int nilfs_direct_propagate(const struct nilfs_bmap *bmap,
struct buffer_head *bh) struct buffer_head *bh)
{ {
struct nilfs_direct *direct; struct nilfs_direct *direct = (struct nilfs_direct *)bmap;
direct = (struct nilfs_direct *)bmap; return NILFS_BMAP_USE_VBN(bmap) ?
return (direct->d_ops->dop_propagate != NULL) ? nilfs_direct_propagate_v(direct, bh) : 0;
direct->d_ops->dop_propagate(direct, bh) :
0;
} }
static int nilfs_direct_assign_v(struct nilfs_direct *direct, static int nilfs_direct_assign_v(struct nilfs_direct *direct,
...@@ -327,12 +355,9 @@ static int nilfs_direct_assign_v(struct nilfs_direct *direct, ...@@ -327,12 +355,9 @@ static int nilfs_direct_assign_v(struct nilfs_direct *direct,
int ret; int ret;
req.bpr_ptr = ptr; req.bpr_ptr = ptr;
ret = direct->d_bmap.b_pops->bpop_prepare_start_ptr( ret = nilfs_bmap_start_v(&direct->d_bmap, &req, blocknr);
&direct->d_bmap, &req); if (unlikely(ret < 0))
if (ret < 0)
return ret; return ret;
direct->d_bmap.b_pops->bpop_commit_start_ptr(&direct->d_bmap,
&req, blocknr);
binfo->bi_v.bi_vblocknr = nilfs_bmap_ptr_to_dptr(ptr); binfo->bi_v.bi_vblocknr = nilfs_bmap_ptr_to_dptr(ptr);
binfo->bi_v.bi_blkoff = nilfs_bmap_key_to_dkey(key); binfo->bi_v.bi_blkoff = nilfs_bmap_key_to_dkey(key);
...@@ -377,12 +402,14 @@ static int nilfs_direct_assign(struct nilfs_bmap *bmap, ...@@ -377,12 +402,14 @@ static int nilfs_direct_assign(struct nilfs_bmap *bmap,
return -EINVAL; return -EINVAL;
} }
return direct->d_ops->dop_assign(direct, key, ptr, bh, return NILFS_BMAP_USE_VBN(bmap) ?
blocknr, binfo); nilfs_direct_assign_v(direct, key, ptr, bh, blocknr, binfo) :
nilfs_direct_assign_p(direct, key, ptr, bh, blocknr, binfo);
} }
static const struct nilfs_bmap_operations nilfs_direct_ops = { static const struct nilfs_bmap_operations nilfs_direct_ops = {
.bop_lookup = nilfs_direct_lookup, .bop_lookup = nilfs_direct_lookup,
.bop_lookup_contig = nilfs_direct_lookup_contig,
.bop_insert = nilfs_direct_insert, .bop_insert = nilfs_direct_insert,
.bop_delete = nilfs_direct_delete, .bop_delete = nilfs_direct_delete,
.bop_clear = NULL, .bop_clear = NULL,
...@@ -401,36 +428,8 @@ static const struct nilfs_bmap_operations nilfs_direct_ops = { ...@@ -401,36 +428,8 @@ static const struct nilfs_bmap_operations nilfs_direct_ops = {
}; };
static const struct nilfs_direct_operations nilfs_direct_ops_v = { int nilfs_direct_init(struct nilfs_bmap *bmap)
.dop_find_target = nilfs_direct_find_target_v,
.dop_set_target = nilfs_direct_set_target_v,
.dop_propagate = nilfs_direct_propagate_v,
.dop_assign = nilfs_direct_assign_v,
};
static const struct nilfs_direct_operations nilfs_direct_ops_p = {
.dop_find_target = NULL,
.dop_set_target = NULL,
.dop_propagate = NULL,
.dop_assign = nilfs_direct_assign_p,
};
int nilfs_direct_init(struct nilfs_bmap *bmap, __u64 low, __u64 high)
{ {
struct nilfs_direct *direct;
direct = (struct nilfs_direct *)bmap;
bmap->b_ops = &nilfs_direct_ops; bmap->b_ops = &nilfs_direct_ops;
bmap->b_low = low;
bmap->b_high = high;
switch (bmap->b_inode->i_ino) {
case NILFS_DAT_INO:
direct->d_ops = &nilfs_direct_ops_p;
break;
default:
direct->d_ops = &nilfs_direct_ops_v;
break;
}
return 0; return 0;
} }
...@@ -30,18 +30,6 @@ ...@@ -30,18 +30,6 @@
struct nilfs_direct; struct nilfs_direct;
/**
* struct nilfs_direct_operations - direct mapping operation table
*/
struct nilfs_direct_operations {
__u64 (*dop_find_target)(const struct nilfs_direct *, __u64);
void (*dop_set_target)(struct nilfs_direct *, __u64, __u64);
int (*dop_propagate)(struct nilfs_direct *, struct buffer_head *);
int (*dop_assign)(struct nilfs_direct *, __u64, __u64,
struct buffer_head **, sector_t,
union nilfs_binfo *);
};
/** /**
* struct nilfs_direct_node - direct node * struct nilfs_direct_node - direct node
* @dn_flags: flags * @dn_flags: flags
...@@ -55,13 +43,9 @@ struct nilfs_direct_node { ...@@ -55,13 +43,9 @@ struct nilfs_direct_node {
/** /**
* struct nilfs_direct - direct mapping * struct nilfs_direct - direct mapping
* @d_bmap: bmap structure * @d_bmap: bmap structure
* @d_ops: direct mapping operation table
*/ */
struct nilfs_direct { struct nilfs_direct {
struct nilfs_bmap d_bmap; struct nilfs_bmap d_bmap;
/* direct-mapping-specific members */
const struct nilfs_direct_operations *d_ops;
}; };
...@@ -70,9 +54,9 @@ struct nilfs_direct { ...@@ -70,9 +54,9 @@ struct nilfs_direct {
#define NILFS_DIRECT_KEY_MAX (NILFS_DIRECT_NBLOCKS - 1) #define NILFS_DIRECT_KEY_MAX (NILFS_DIRECT_NBLOCKS - 1)
int nilfs_direct_init(struct nilfs_bmap *, __u64, __u64); int nilfs_direct_init(struct nilfs_bmap *);
int nilfs_direct_delete_and_convert(struct nilfs_bmap *, __u64, __u64 *, int nilfs_direct_delete_and_convert(struct nilfs_bmap *, __u64, __u64 *,
__u64 *, int, __u64, __u64); __u64 *, int);
#endif /* _NILFS_DIRECT_H */ #endif /* _NILFS_DIRECT_H */
...@@ -52,8 +52,9 @@ ...@@ -52,8 +52,9 @@
#include "dat.h" #include "dat.h"
#include "ifile.h" #include "ifile.h"
static struct address_space_operations def_gcinode_aops = {}; static struct address_space_operations def_gcinode_aops = {
/* XXX need def_gcinode_iops/fops? */ .sync_page = block_sync_page,
};
/* /*
* nilfs_gccache_submit_read_data() - add data buffer and submit read request * nilfs_gccache_submit_read_data() - add data buffer and submit read request
......
...@@ -43,22 +43,23 @@ ...@@ -43,22 +43,23 @@
* *
* This function does not issue actual read request of the specified data * This function does not issue actual read request of the specified data
* block. It is done by VFS. * block. It is done by VFS.
* Bulk read for direct-io is not supported yet. (should be supported)
*/ */
int nilfs_get_block(struct inode *inode, sector_t blkoff, int nilfs_get_block(struct inode *inode, sector_t blkoff,
struct buffer_head *bh_result, int create) struct buffer_head *bh_result, int create)
{ {
struct nilfs_inode_info *ii = NILFS_I(inode); struct nilfs_inode_info *ii = NILFS_I(inode);
unsigned long blknum = 0; __u64 blknum = 0;
int err = 0, ret; int err = 0, ret;
struct inode *dat = nilfs_dat_inode(NILFS_I_NILFS(inode)); struct inode *dat = nilfs_dat_inode(NILFS_I_NILFS(inode));
unsigned maxblocks = bh_result->b_size >> inode->i_blkbits;
/* This exclusion control is a workaround; should be revised */ down_read(&NILFS_MDT(dat)->mi_sem);
down_read(&NILFS_MDT(dat)->mi_sem); /* XXX */ ret = nilfs_bmap_lookup_contig(ii->i_bmap, blkoff, &blknum, maxblocks);
ret = nilfs_bmap_lookup(ii->i_bmap, (unsigned long)blkoff, &blknum); up_read(&NILFS_MDT(dat)->mi_sem);
up_read(&NILFS_MDT(dat)->mi_sem); /* XXX */ if (ret >= 0) { /* found */
if (ret == 0) { /* found */
map_bh(bh_result, inode->i_sb, blknum); map_bh(bh_result, inode->i_sb, blknum);
if (ret > 0)
bh_result->b_size = (ret << inode->i_blkbits);
goto out; goto out;
} }
/* data block was not found */ /* data block was not found */
...@@ -240,7 +241,7 @@ nilfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, ...@@ -240,7 +241,7 @@ nilfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
struct address_space_operations nilfs_aops = { struct address_space_operations nilfs_aops = {
.writepage = nilfs_writepage, .writepage = nilfs_writepage,
.readpage = nilfs_readpage, .readpage = nilfs_readpage,
/* .sync_page = nilfs_sync_page, */ .sync_page = block_sync_page,
.writepages = nilfs_writepages, .writepages = nilfs_writepages,
.set_page_dirty = nilfs_set_page_dirty, .set_page_dirty = nilfs_set_page_dirty,
.readpages = nilfs_readpages, .readpages = nilfs_readpages,
...@@ -249,6 +250,7 @@ struct address_space_operations nilfs_aops = { ...@@ -249,6 +250,7 @@ struct address_space_operations nilfs_aops = {
/* .releasepage = nilfs_releasepage, */ /* .releasepage = nilfs_releasepage, */
.invalidatepage = block_invalidatepage, .invalidatepage = block_invalidatepage,
.direct_IO = nilfs_direct_IO, .direct_IO = nilfs_direct_IO,
.is_partially_uptodate = block_is_partially_uptodate,
}; };
struct inode *nilfs_new_inode(struct inode *dir, int mode) struct inode *nilfs_new_inode(struct inode *dir, int mode)
......
...@@ -152,7 +152,7 @@ nilfs_ioctl_do_get_cpinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, ...@@ -152,7 +152,7 @@ nilfs_ioctl_do_get_cpinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
down_read(&nilfs->ns_segctor_sem); down_read(&nilfs->ns_segctor_sem);
ret = nilfs_cpfile_get_cpinfo(nilfs->ns_cpfile, posp, flags, buf, ret = nilfs_cpfile_get_cpinfo(nilfs->ns_cpfile, posp, flags, buf,
nmembs); size, nmembs);
up_read(&nilfs->ns_segctor_sem); up_read(&nilfs->ns_segctor_sem);
return ret; return ret;
} }
...@@ -182,7 +182,8 @@ nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, ...@@ -182,7 +182,8 @@ nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
int ret; int ret;
down_read(&nilfs->ns_segctor_sem); down_read(&nilfs->ns_segctor_sem);
ret = nilfs_sufile_get_suinfo(nilfs->ns_sufile, *posp, buf, nmembs); ret = nilfs_sufile_get_suinfo(nilfs->ns_sufile, *posp, buf, size,
nmembs);
up_read(&nilfs->ns_segctor_sem); up_read(&nilfs->ns_segctor_sem);
return ret; return ret;
} }
...@@ -212,7 +213,7 @@ nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, ...@@ -212,7 +213,7 @@ nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
int ret; int ret;
down_read(&nilfs->ns_segctor_sem); down_read(&nilfs->ns_segctor_sem);
ret = nilfs_dat_get_vinfo(nilfs_dat_inode(nilfs), buf, nmembs); ret = nilfs_dat_get_vinfo(nilfs_dat_inode(nilfs), buf, size, nmembs);
up_read(&nilfs->ns_segctor_sem); up_read(&nilfs->ns_segctor_sem);
return ret; return ret;
} }
...@@ -435,24 +436,6 @@ static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs, ...@@ -435,24 +436,6 @@ static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs,
return nmembs; return nmembs;
} }
static int nilfs_ioctl_free_segments(struct the_nilfs *nilfs,
struct nilfs_argv *argv, void *buf)
{
size_t nmembs = argv->v_nmembs;
struct nilfs_sb_info *sbi = nilfs->ns_writer;
int ret;
if (unlikely(!sbi)) {
/* never happens because called for a writable mount */
WARN_ON(1);
return -EROFS;
}
ret = nilfs_segctor_add_segments_to_be_freed(
NILFS_SC(sbi), buf, nmembs);
return (ret < 0) ? ret : nmembs;
}
int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs,
struct nilfs_argv *argv, void **kbufs) struct nilfs_argv *argv, void **kbufs)
{ {
...@@ -491,14 +474,6 @@ int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, ...@@ -491,14 +474,6 @@ int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs,
msg = "cannot mark copying blocks dirty"; msg = "cannot mark copying blocks dirty";
goto failed; goto failed;
} }
ret = nilfs_ioctl_free_segments(nilfs, &argv[4], kbufs[4]);
if (ret < 0) {
/*
* can safely abort because this operation is atomic.
*/
msg = "cannot set segments to be freed";
goto failed;
}
return 0; return 0;
failed: failed:
...@@ -615,7 +590,7 @@ static int nilfs_ioctl_get_info(struct inode *inode, struct file *filp, ...@@ -615,7 +590,7 @@ static int nilfs_ioctl_get_info(struct inode *inode, struct file *filp,
if (copy_from_user(&argv, argp, sizeof(argv))) if (copy_from_user(&argv, argp, sizeof(argv)))
return -EFAULT; return -EFAULT;
if (argv.v_size != membsz) if (argv.v_size < membsz)
return -EINVAL; return -EINVAL;
ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), dofunc); ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), dofunc);
......
...@@ -430,6 +430,7 @@ nilfs_mdt_write_page(struct page *page, struct writeback_control *wbc) ...@@ -430,6 +430,7 @@ nilfs_mdt_write_page(struct page *page, struct writeback_control *wbc)
static struct address_space_operations def_mdt_aops = { static struct address_space_operations def_mdt_aops = {
.writepage = nilfs_mdt_write_page, .writepage = nilfs_mdt_write_page,
.sync_page = block_sync_page,
}; };
static struct inode_operations def_mdt_iops; static struct inode_operations def_mdt_iops;
...@@ -449,7 +450,7 @@ struct inode * ...@@ -449,7 +450,7 @@ struct inode *
nilfs_mdt_new_common(struct the_nilfs *nilfs, struct super_block *sb, nilfs_mdt_new_common(struct the_nilfs *nilfs, struct super_block *sb,
ino_t ino, gfp_t gfp_mask) ino_t ino, gfp_t gfp_mask)
{ {
struct inode *inode = nilfs_alloc_inode(sb); struct inode *inode = nilfs_alloc_inode_common(nilfs);
if (!inode) if (!inode)
return NULL; return NULL;
......
...@@ -263,6 +263,7 @@ extern void nilfs_dirty_inode(struct inode *); ...@@ -263,6 +263,7 @@ extern void nilfs_dirty_inode(struct inode *);
extern struct dentry *nilfs_get_parent(struct dentry *); extern struct dentry *nilfs_get_parent(struct dentry *);
/* super.c */ /* super.c */
extern struct inode *nilfs_alloc_inode_common(struct the_nilfs *);
extern struct inode *nilfs_alloc_inode(struct super_block *); extern struct inode *nilfs_alloc_inode(struct super_block *);
extern void nilfs_destroy_inode(struct inode *); extern void nilfs_destroy_inode(struct inode *);
extern void nilfs_error(struct super_block *, const char *, const char *, ...) extern void nilfs_error(struct super_block *, const char *, const char *, ...)
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
#include "segment.h" #include "segment.h"
#include "sufile.h" #include "sufile.h"
#include "page.h" #include "page.h"
#include "seglist.h"
#include "segbuf.h" #include "segbuf.h"
/* /*
...@@ -395,6 +394,24 @@ static void dispose_recovery_list(struct list_head *head) ...@@ -395,6 +394,24 @@ static void dispose_recovery_list(struct list_head *head)
} }
} }
struct nilfs_segment_entry {
struct list_head list;
__u64 segnum;
};
static int nilfs_segment_list_add(struct list_head *head, __u64 segnum)
{
struct nilfs_segment_entry *ent = kmalloc(sizeof(*ent), GFP_NOFS);
if (unlikely(!ent))
return -ENOMEM;
ent->segnum = segnum;
INIT_LIST_HEAD(&ent->list);
list_add_tail(&ent->list, head);
return 0;
}
void nilfs_dispose_segment_list(struct list_head *head) void nilfs_dispose_segment_list(struct list_head *head)
{ {
while (!list_empty(head)) { while (!list_empty(head)) {
...@@ -402,7 +419,7 @@ void nilfs_dispose_segment_list(struct list_head *head) ...@@ -402,7 +419,7 @@ void nilfs_dispose_segment_list(struct list_head *head)
= list_entry(head->next, = list_entry(head->next,
struct nilfs_segment_entry, list); struct nilfs_segment_entry, list);
list_del(&ent->list); list_del(&ent->list);
nilfs_free_segment_entry(ent); kfree(ent);
} }
} }
...@@ -431,12 +448,10 @@ static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs, ...@@ -431,12 +448,10 @@ static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs,
if (unlikely(err)) if (unlikely(err))
goto failed; goto failed;
err = -ENOMEM;
for (i = 1; i < 4; i++) { for (i = 1; i < 4; i++) {
ent = nilfs_alloc_segment_entry(segnum[i]); err = nilfs_segment_list_add(head, segnum[i]);
if (unlikely(!ent)) if (unlikely(err))
goto failed; goto failed;
list_add_tail(&ent->list, head);
} }
/* /*
...@@ -450,7 +465,7 @@ static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs, ...@@ -450,7 +465,7 @@ static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs,
goto failed; goto failed;
} }
list_del(&ent->list); list_del(&ent->list);
nilfs_free_segment_entry(ent); kfree(ent);
} }
/* Allocate new segments for recovery */ /* Allocate new segments for recovery */
...@@ -791,7 +806,6 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, ...@@ -791,7 +806,6 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
u64 seg_seq; u64 seg_seq;
__u64 segnum, nextnum = 0; __u64 segnum, nextnum = 0;
__u64 cno; __u64 cno;
struct nilfs_segment_entry *ent;
LIST_HEAD(segments); LIST_HEAD(segments);
int empty_seg = 0, scan_newer = 0; int empty_seg = 0, scan_newer = 0;
int ret; int ret;
...@@ -892,12 +906,9 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, ...@@ -892,12 +906,9 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
if (empty_seg++) if (empty_seg++)
goto super_root_found; /* found a valid super root */ goto super_root_found; /* found a valid super root */
ent = nilfs_alloc_segment_entry(segnum); ret = nilfs_segment_list_add(&segments, segnum);
if (unlikely(!ent)) { if (unlikely(ret))
ret = -ENOMEM;
goto failed; goto failed;
}
list_add_tail(&ent->list, &segments);
seg_seq++; seg_seq++;
segnum = nextnum; segnum = nextnum;
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#include <linux/crc32.h> #include <linux/crc32.h>
#include "page.h" #include "page.h"
#include "segbuf.h" #include "segbuf.h"
#include "seglist.h"
static struct kmem_cache *nilfs_segbuf_cachep; static struct kmem_cache *nilfs_segbuf_cachep;
...@@ -394,7 +393,7 @@ int nilfs_segbuf_write(struct nilfs_segment_buffer *segbuf, ...@@ -394,7 +393,7 @@ int nilfs_segbuf_write(struct nilfs_segment_buffer *segbuf,
* Last BIO is always sent through the following * Last BIO is always sent through the following
* submission. * submission.
*/ */
rw |= (1 << BIO_RW_SYNCIO); rw |= (1 << BIO_RW_SYNCIO) | (1 << BIO_RW_UNPLUG);
res = nilfs_submit_seg_bio(wi, rw); res = nilfs_submit_seg_bio(wi, rw);
if (unlikely(res)) if (unlikely(res))
goto failed_bio; goto failed_bio;
......
/*
* seglist.h - expediential structure and routines to handle list of segments
* (would be removed in a future release)
*
* Copyright (C) 2005-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 Ryusuke Konishi <ryusuke@osrg.net>
*
*/
#ifndef _NILFS_SEGLIST_H
#define _NILFS_SEGLIST_H
#include <linux/fs.h>
#include <linux/buffer_head.h>
#include <linux/nilfs2_fs.h>
#include "sufile.h"
struct nilfs_segment_entry {
__u64 segnum;
#define NILFS_SLH_FREED 0x0001 /* The segment was freed provisonally.
It must be cancelled if
construction aborted */
unsigned flags;
struct list_head list;
struct buffer_head *bh_su;
struct nilfs_segment_usage *raw_su;
};
void nilfs_dispose_segment_list(struct list_head *);
static inline struct nilfs_segment_entry *
nilfs_alloc_segment_entry(__u64 segnum)
{
struct nilfs_segment_entry *ent = kmalloc(sizeof(*ent), GFP_NOFS);
if (likely(ent)) {
ent->segnum = segnum;
ent->flags = 0;
ent->bh_su = NULL;
ent->raw_su = NULL;
INIT_LIST_HEAD(&ent->list);
}
return ent;
}
static inline int nilfs_open_segment_entry(struct nilfs_segment_entry *ent,
struct inode *sufile)
{
return nilfs_sufile_get_segment_usage(sufile, ent->segnum,
&ent->raw_su, &ent->bh_su);
}
static inline void nilfs_close_segment_entry(struct nilfs_segment_entry *ent,
struct inode *sufile)
{
if (!ent->bh_su)
return;
nilfs_sufile_put_segment_usage(sufile, ent->segnum, ent->bh_su);
ent->bh_su = NULL;
ent->raw_su = NULL;
}
static inline void nilfs_free_segment_entry(struct nilfs_segment_entry *ent)
{
kfree(ent);
}
#endif /* _NILFS_SEGLIST_H */
...@@ -39,7 +39,6 @@ ...@@ -39,7 +39,6 @@
#include "sufile.h" #include "sufile.h"
#include "cpfile.h" #include "cpfile.h"
#include "ifile.h" #include "ifile.h"
#include "seglist.h"
#include "segbuf.h" #include "segbuf.h"
...@@ -79,7 +78,8 @@ enum { ...@@ -79,7 +78,8 @@ enum {
/* State flags of collection */ /* State flags of collection */
#define NILFS_CF_NODE 0x0001 /* Collecting node blocks */ #define NILFS_CF_NODE 0x0001 /* Collecting node blocks */
#define NILFS_CF_IFILE_STARTED 0x0002 /* IFILE stage has started */ #define NILFS_CF_IFILE_STARTED 0x0002 /* IFILE stage has started */
#define NILFS_CF_HISTORY_MASK (NILFS_CF_IFILE_STARTED) #define NILFS_CF_SUFREED 0x0004 /* segment usages has been freed */
#define NILFS_CF_HISTORY_MASK (NILFS_CF_IFILE_STARTED | NILFS_CF_SUFREED)
/* Operations depending on the construction mode and file type */ /* Operations depending on the construction mode and file type */
struct nilfs_sc_operations { struct nilfs_sc_operations {
...@@ -810,7 +810,7 @@ static int nilfs_segctor_clean(struct nilfs_sc_info *sci) ...@@ -810,7 +810,7 @@ static int nilfs_segctor_clean(struct nilfs_sc_info *sci)
{ {
return list_empty(&sci->sc_dirty_files) && return list_empty(&sci->sc_dirty_files) &&
!test_bit(NILFS_SC_DIRTY, &sci->sc_flags) && !test_bit(NILFS_SC_DIRTY, &sci->sc_flags) &&
list_empty(&sci->sc_cleaning_segments) && sci->sc_nfreesegs == 0 &&
(!nilfs_doing_gc() || list_empty(&sci->sc_gc_inodes)); (!nilfs_doing_gc() || list_empty(&sci->sc_gc_inodes));
} }
...@@ -1005,44 +1005,6 @@ static void nilfs_drop_collected_inodes(struct list_head *head) ...@@ -1005,44 +1005,6 @@ static void nilfs_drop_collected_inodes(struct list_head *head)
} }
} }
static void nilfs_segctor_cancel_free_segments(struct nilfs_sc_info *sci,
struct inode *sufile)
{
struct list_head *head = &sci->sc_cleaning_segments;
struct nilfs_segment_entry *ent;
int err;
list_for_each_entry(ent, head, list) {
if (!(ent->flags & NILFS_SLH_FREED))
break;
err = nilfs_sufile_cancel_free(sufile, ent->segnum);
WARN_ON(err); /* do not happen */
ent->flags &= ~NILFS_SLH_FREED;
}
}
static int nilfs_segctor_prepare_free_segments(struct nilfs_sc_info *sci,
struct inode *sufile)
{
struct list_head *head = &sci->sc_cleaning_segments;
struct nilfs_segment_entry *ent;
int err;
list_for_each_entry(ent, head, list) {
err = nilfs_sufile_free(sufile, ent->segnum);
if (unlikely(err))
return err;
ent->flags |= NILFS_SLH_FREED;
}
return 0;
}
static void nilfs_segctor_commit_free_segments(struct nilfs_sc_info *sci)
{
nilfs_dispose_segment_list(&sci->sc_cleaning_segments);
}
static int nilfs_segctor_apply_buffers(struct nilfs_sc_info *sci, static int nilfs_segctor_apply_buffers(struct nilfs_sc_info *sci,
struct inode *inode, struct inode *inode,
struct list_head *listp, struct list_head *listp,
...@@ -1161,6 +1123,7 @@ static int nilfs_segctor_collect_blocks(struct nilfs_sc_info *sci, int mode) ...@@ -1161,6 +1123,7 @@ static int nilfs_segctor_collect_blocks(struct nilfs_sc_info *sci, int mode)
struct the_nilfs *nilfs = sbi->s_nilfs; struct the_nilfs *nilfs = sbi->s_nilfs;
struct list_head *head; struct list_head *head;
struct nilfs_inode_info *ii; struct nilfs_inode_info *ii;
size_t ndone;
int err = 0; int err = 0;
switch (sci->sc_stage.scnt) { switch (sci->sc_stage.scnt) {
...@@ -1250,10 +1213,16 @@ static int nilfs_segctor_collect_blocks(struct nilfs_sc_info *sci, int mode) ...@@ -1250,10 +1213,16 @@ static int nilfs_segctor_collect_blocks(struct nilfs_sc_info *sci, int mode)
break; break;
sci->sc_stage.scnt++; /* Fall through */ sci->sc_stage.scnt++; /* Fall through */
case NILFS_ST_SUFILE: case NILFS_ST_SUFILE:
err = nilfs_segctor_prepare_free_segments(sci, err = nilfs_sufile_freev(nilfs->ns_sufile, sci->sc_freesegs,
nilfs->ns_sufile); sci->sc_nfreesegs, &ndone);
if (unlikely(err)) if (unlikely(err)) {
nilfs_sufile_cancel_freev(nilfs->ns_sufile,
sci->sc_freesegs, ndone,
NULL);
break; break;
}
sci->sc_stage.flags |= NILFS_CF_SUFREED;
err = nilfs_segctor_scan_file(sci, nilfs->ns_sufile, err = nilfs_segctor_scan_file(sci, nilfs->ns_sufile,
&nilfs_sc_file_ops); &nilfs_sc_file_ops);
if (unlikely(err)) if (unlikely(err))
...@@ -1486,7 +1455,15 @@ static void nilfs_segctor_end_construction(struct nilfs_sc_info *sci, ...@@ -1486,7 +1455,15 @@ static void nilfs_segctor_end_construction(struct nilfs_sc_info *sci,
{ {
if (unlikely(err)) { if (unlikely(err)) {
nilfs_segctor_free_incomplete_segments(sci, nilfs); nilfs_segctor_free_incomplete_segments(sci, nilfs);
nilfs_segctor_cancel_free_segments(sci, nilfs->ns_sufile); if (sci->sc_stage.flags & NILFS_CF_SUFREED) {
int ret;
ret = nilfs_sufile_cancel_freev(nilfs->ns_sufile,
sci->sc_freesegs,
sci->sc_nfreesegs,
NULL);
WARN_ON(ret); /* do not happen */
}
} }
nilfs_segctor_clear_segment_buffers(sci); nilfs_segctor_clear_segment_buffers(sci);
} }
...@@ -1585,7 +1562,13 @@ static int nilfs_segctor_collect(struct nilfs_sc_info *sci, ...@@ -1585,7 +1562,13 @@ static int nilfs_segctor_collect(struct nilfs_sc_info *sci,
if (mode != SC_LSEG_SR || sci->sc_stage.scnt < NILFS_ST_CPFILE) if (mode != SC_LSEG_SR || sci->sc_stage.scnt < NILFS_ST_CPFILE)
break; break;
nilfs_segctor_cancel_free_segments(sci, nilfs->ns_sufile); if (sci->sc_stage.flags & NILFS_CF_SUFREED) {
err = nilfs_sufile_cancel_freev(nilfs->ns_sufile,
sci->sc_freesegs,
sci->sc_nfreesegs,
NULL);
WARN_ON(err); /* do not happen */
}
nilfs_segctor_clear_segment_buffers(sci); nilfs_segctor_clear_segment_buffers(sci);
err = nilfs_segctor_extend_segments(sci, nilfs, nadd); err = nilfs_segctor_extend_segments(sci, nilfs, nadd);
...@@ -2224,10 +2207,8 @@ static int nilfs_segctor_do_construct(struct nilfs_sc_info *sci, int mode) ...@@ -2224,10 +2207,8 @@ static int nilfs_segctor_do_construct(struct nilfs_sc_info *sci, int mode)
nilfs_segctor_complete_write(sci); nilfs_segctor_complete_write(sci);
/* Commit segments */ /* Commit segments */
if (has_sr) { if (has_sr)
nilfs_segctor_commit_free_segments(sci);
nilfs_segctor_clear_metadata_dirty(sci); nilfs_segctor_clear_metadata_dirty(sci);
}
nilfs_segctor_end_construction(sci, nilfs, 0); nilfs_segctor_end_construction(sci, nilfs, 0);
...@@ -2301,48 +2282,6 @@ void nilfs_flush_segment(struct super_block *sb, ino_t ino) ...@@ -2301,48 +2282,6 @@ void nilfs_flush_segment(struct super_block *sb, ino_t ino)
/* assign bit 0 to data files */ /* assign bit 0 to data files */
} }
int nilfs_segctor_add_segments_to_be_freed(struct nilfs_sc_info *sci,
__u64 *segnum, size_t nsegs)
{
struct nilfs_segment_entry *ent;
struct the_nilfs *nilfs = sci->sc_sbi->s_nilfs;
struct inode *sufile = nilfs->ns_sufile;
LIST_HEAD(list);
__u64 *pnum;
size_t i;
int err;
for (pnum = segnum, i = 0; i < nsegs; pnum++, i++) {
ent = nilfs_alloc_segment_entry(*pnum);
if (unlikely(!ent)) {
err = -ENOMEM;
goto failed;
}
list_add_tail(&ent->list, &list);
err = nilfs_open_segment_entry(ent, sufile);
if (unlikely(err))
goto failed;
if (unlikely(!nilfs_segment_usage_dirty(ent->raw_su)))
printk(KERN_WARNING "NILFS: unused segment is "
"requested to be cleaned (segnum=%llu)\n",
(unsigned long long)ent->segnum);
nilfs_close_segment_entry(ent, sufile);
}
list_splice(&list, sci->sc_cleaning_segments.prev);
return 0;
failed:
nilfs_dispose_segment_list(&list);
return err;
}
void nilfs_segctor_clear_segments_to_be_freed(struct nilfs_sc_info *sci)
{
nilfs_dispose_segment_list(&sci->sc_cleaning_segments);
}
struct nilfs_segctor_wait_request { struct nilfs_segctor_wait_request {
wait_queue_t wq; wait_queue_t wq;
__u32 seq; __u32 seq;
...@@ -2607,10 +2546,13 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv, ...@@ -2607,10 +2546,13 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv,
err = nilfs_init_gcdat_inode(nilfs); err = nilfs_init_gcdat_inode(nilfs);
if (unlikely(err)) if (unlikely(err))
goto out_unlock; goto out_unlock;
err = nilfs_ioctl_prepare_clean_segments(nilfs, argv, kbufs); err = nilfs_ioctl_prepare_clean_segments(nilfs, argv, kbufs);
if (unlikely(err)) if (unlikely(err))
goto out_unlock; goto out_unlock;
sci->sc_freesegs = kbufs[4];
sci->sc_nfreesegs = argv[4].v_nmembs;
list_splice_init(&nilfs->ns_gc_inodes, sci->sc_gc_inodes.prev); list_splice_init(&nilfs->ns_gc_inodes, sci->sc_gc_inodes.prev);
for (;;) { for (;;) {
...@@ -2629,6 +2571,8 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv, ...@@ -2629,6 +2571,8 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv,
} }
out_unlock: out_unlock:
sci->sc_freesegs = NULL;
sci->sc_nfreesegs = 0;
nilfs_clear_gcdat_inode(nilfs); nilfs_clear_gcdat_inode(nilfs);
nilfs_transaction_unlock(sbi); nilfs_transaction_unlock(sbi);
return err; return err;
...@@ -2835,7 +2779,6 @@ static struct nilfs_sc_info *nilfs_segctor_new(struct nilfs_sb_info *sbi) ...@@ -2835,7 +2779,6 @@ static struct nilfs_sc_info *nilfs_segctor_new(struct nilfs_sb_info *sbi)
INIT_LIST_HEAD(&sci->sc_dirty_files); INIT_LIST_HEAD(&sci->sc_dirty_files);
INIT_LIST_HEAD(&sci->sc_segbufs); INIT_LIST_HEAD(&sci->sc_segbufs);
INIT_LIST_HEAD(&sci->sc_gc_inodes); INIT_LIST_HEAD(&sci->sc_gc_inodes);
INIT_LIST_HEAD(&sci->sc_cleaning_segments);
INIT_LIST_HEAD(&sci->sc_copied_buffers); INIT_LIST_HEAD(&sci->sc_copied_buffers);
sci->sc_interval = HZ * NILFS_SC_DEFAULT_TIMEOUT; sci->sc_interval = HZ * NILFS_SC_DEFAULT_TIMEOUT;
...@@ -2901,9 +2844,6 @@ static void nilfs_segctor_destroy(struct nilfs_sc_info *sci) ...@@ -2901,9 +2844,6 @@ static void nilfs_segctor_destroy(struct nilfs_sc_info *sci)
nilfs_dispose_list(sbi, &sci->sc_dirty_files, 1); nilfs_dispose_list(sbi, &sci->sc_dirty_files, 1);
} }
if (!list_empty(&sci->sc_cleaning_segments))
nilfs_dispose_segment_list(&sci->sc_cleaning_segments);
WARN_ON(!list_empty(&sci->sc_segbufs)); WARN_ON(!list_empty(&sci->sc_segbufs));
down_write(&sbi->s_nilfs->ns_segctor_sem); down_write(&sbi->s_nilfs->ns_segctor_sem);
......
...@@ -90,8 +90,9 @@ struct nilfs_segsum_pointer { ...@@ -90,8 +90,9 @@ struct nilfs_segsum_pointer {
* @sc_nblk_inc: Block count of current generation * @sc_nblk_inc: Block count of current generation
* @sc_dirty_files: List of files to be written * @sc_dirty_files: List of files to be written
* @sc_gc_inodes: List of GC inodes having blocks to be written * @sc_gc_inodes: List of GC inodes having blocks to be written
* @sc_cleaning_segments: List of segments to be freed through construction
* @sc_copied_buffers: List of copied buffers (buffer heads) to freeze data * @sc_copied_buffers: List of copied buffers (buffer heads) to freeze data
* @sc_freesegs: array of segment numbers to be freed
* @sc_nfreesegs: number of segments on @sc_freesegs
* @sc_dsync_inode: inode whose data pages are written for a sync operation * @sc_dsync_inode: inode whose data pages are written for a sync operation
* @sc_dsync_start: start byte offset of data pages * @sc_dsync_start: start byte offset of data pages
* @sc_dsync_end: end byte offset of data pages (inclusive) * @sc_dsync_end: end byte offset of data pages (inclusive)
...@@ -131,9 +132,11 @@ struct nilfs_sc_info { ...@@ -131,9 +132,11 @@ struct nilfs_sc_info {
struct list_head sc_dirty_files; struct list_head sc_dirty_files;
struct list_head sc_gc_inodes; struct list_head sc_gc_inodes;
struct list_head sc_cleaning_segments;
struct list_head sc_copied_buffers; struct list_head sc_copied_buffers;
__u64 *sc_freesegs;
size_t sc_nfreesegs;
struct nilfs_inode_info *sc_dsync_inode; struct nilfs_inode_info *sc_dsync_inode;
loff_t sc_dsync_start; loff_t sc_dsync_start;
loff_t sc_dsync_end; loff_t sc_dsync_end;
...@@ -225,10 +228,6 @@ extern void nilfs_flush_segment(struct super_block *, ino_t); ...@@ -225,10 +228,6 @@ extern void nilfs_flush_segment(struct super_block *, ino_t);
extern int nilfs_clean_segments(struct super_block *, struct nilfs_argv *, extern int nilfs_clean_segments(struct super_block *, struct nilfs_argv *,
void **); void **);
extern int nilfs_segctor_add_segments_to_be_freed(struct nilfs_sc_info *,
__u64 *, size_t);
extern void nilfs_segctor_clear_segments_to_be_freed(struct nilfs_sc_info *);
extern int nilfs_attach_segment_constructor(struct nilfs_sb_info *); 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 *);
...@@ -240,5 +239,6 @@ extern int nilfs_search_super_root(struct the_nilfs *, struct nilfs_sb_info *, ...@@ -240,5 +239,6 @@ extern int nilfs_search_super_root(struct the_nilfs *, struct nilfs_sb_info *,
extern int nilfs_recover_logical_segments(struct the_nilfs *, extern int nilfs_recover_logical_segments(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 *);
#endif /* _NILFS_SEGMENT_H */ #endif /* _NILFS_SEGMENT_H */
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* *
* Written by Koji Sato <koji@osrg.net>. * Written by Koji Sato <koji@osrg.net>.
* Rivised by Ryusuke Konishi <ryusuke@osrg.net>.
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -108,6 +109,102 @@ static void nilfs_sufile_mod_counter(struct buffer_head *header_bh, ...@@ -108,6 +109,102 @@ static void nilfs_sufile_mod_counter(struct buffer_head *header_bh,
nilfs_mdt_mark_buffer_dirty(header_bh); nilfs_mdt_mark_buffer_dirty(header_bh);
} }
/**
* nilfs_sufile_updatev - modify multiple segment usages at a time
* @sufile: inode of segment usage file
* @segnumv: array of segment numbers
* @nsegs: size of @segnumv array
* @create: creation flag
* @ndone: place to store number of modified segments on @segnumv
* @dofunc: primitive operation for the update
*
* Description: nilfs_sufile_updatev() repeatedly calls @dofunc
* against the given array of segments. The @dofunc is called with
* buffers of a header block and the sufile block in which the target
* segment usage entry is contained. If @ndone is given, the number
* of successfully modified segments from the head is stored in the
* place @ndone points to.
*
* Return Value: On success, zero is returned. On error, one of the
* following negative error codes is returned.
*
* %-EIO - I/O error.
*
* %-ENOMEM - Insufficient amount of memory available.
*
* %-ENOENT - Given segment usage is in hole block (may be returned if
* @create is zero)
*
* %-EINVAL - Invalid segment usage number
*/
int nilfs_sufile_updatev(struct inode *sufile, __u64 *segnumv, size_t nsegs,
int create, size_t *ndone,
void (*dofunc)(struct inode *, __u64,
struct buffer_head *,
struct buffer_head *))
{
struct buffer_head *header_bh, *bh;
unsigned long blkoff, prev_blkoff;
__u64 *seg;
size_t nerr = 0, n = 0;
int ret = 0;
if (unlikely(nsegs == 0))
goto out;
down_write(&NILFS_MDT(sufile)->mi_sem);
for (seg = segnumv; seg < segnumv + nsegs; seg++) {
if (unlikely(*seg >= nilfs_sufile_get_nsegments(sufile))) {
printk(KERN_WARNING
"%s: invalid segment number: %llu\n", __func__,
(unsigned long long)*seg);
nerr++;
}
}
if (nerr > 0) {
ret = -EINVAL;
goto out_sem;
}
ret = nilfs_sufile_get_header_block(sufile, &header_bh);
if (ret < 0)
goto out_sem;
seg = segnumv;
blkoff = nilfs_sufile_get_blkoff(sufile, *seg);
ret = nilfs_mdt_get_block(sufile, blkoff, create, NULL, &bh);
if (ret < 0)
goto out_header;
for (;;) {
dofunc(sufile, *seg, header_bh, bh);
if (++seg >= segnumv + nsegs)
break;
prev_blkoff = blkoff;
blkoff = nilfs_sufile_get_blkoff(sufile, *seg);
if (blkoff == prev_blkoff)
continue;
/* get different block */
brelse(bh);
ret = nilfs_mdt_get_block(sufile, blkoff, create, NULL, &bh);
if (unlikely(ret < 0))
goto out_header;
}
brelse(bh);
out_header:
n = seg - segnumv;
brelse(header_bh);
out_sem:
up_write(&NILFS_MDT(sufile)->mi_sem);
out:
if (ndone)
*ndone = n;
return ret;
}
int nilfs_sufile_update(struct inode *sufile, __u64 segnum, int create, int nilfs_sufile_update(struct inode *sufile, __u64 segnum, int create,
void (*dofunc)(struct inode *, __u64, void (*dofunc)(struct inode *, __u64,
struct buffer_head *, struct buffer_head *,
...@@ -490,7 +587,8 @@ void nilfs_sufile_do_set_error(struct inode *sufile, __u64 segnum, ...@@ -490,7 +587,8 @@ void nilfs_sufile_do_set_error(struct inode *sufile, __u64 segnum,
* nilfs_sufile_get_suinfo - * nilfs_sufile_get_suinfo -
* @sufile: inode of segment usage file * @sufile: inode of segment usage file
* @segnum: segment number to start looking * @segnum: segment number to start looking
* @si: array of suinfo * @buf: array of suinfo
* @sisz: byte size of suinfo
* @nsi: size of suinfo array * @nsi: size of suinfo array
* *
* Description: * Description:
...@@ -502,11 +600,12 @@ void nilfs_sufile_do_set_error(struct inode *sufile, __u64 segnum, ...@@ -502,11 +600,12 @@ void nilfs_sufile_do_set_error(struct inode *sufile, __u64 segnum,
* *
* %-ENOMEM - Insufficient amount of memory available. * %-ENOMEM - Insufficient amount of memory available.
*/ */
ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf,
struct nilfs_suinfo *si, size_t nsi) unsigned sisz, size_t nsi)
{ {
struct buffer_head *su_bh; struct buffer_head *su_bh;
struct nilfs_segment_usage *su; struct nilfs_segment_usage *su;
struct nilfs_suinfo *si = buf;
size_t susz = NILFS_MDT(sufile)->mi_entry_size; size_t susz = NILFS_MDT(sufile)->mi_entry_size;
struct the_nilfs *nilfs = NILFS_MDT(sufile)->mi_nilfs; struct the_nilfs *nilfs = NILFS_MDT(sufile)->mi_nilfs;
void *kaddr; void *kaddr;
...@@ -531,20 +630,22 @@ ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, ...@@ -531,20 +630,22 @@ ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum,
if (ret != -ENOENT) if (ret != -ENOENT)
goto out; goto out;
/* hole */ /* hole */
memset(&si[i], 0, sizeof(struct nilfs_suinfo) * n); memset(si, 0, sisz * n);
si = (void *)si + sisz * n;
continue; continue;
} }
kaddr = kmap_atomic(su_bh->b_page, KM_USER0); kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
su = nilfs_sufile_block_get_segment_usage( su = nilfs_sufile_block_get_segment_usage(
sufile, segnum, su_bh, kaddr); sufile, segnum, su_bh, kaddr);
for (j = 0; j < n; j++, su = (void *)su + susz) { for (j = 0; j < n;
si[i + j].sui_lastmod = le64_to_cpu(su->su_lastmod); j++, su = (void *)su + susz, si = (void *)si + sisz) {
si[i + j].sui_nblocks = le32_to_cpu(su->su_nblocks); si->sui_lastmod = le64_to_cpu(su->su_lastmod);
si[i + j].sui_flags = le32_to_cpu(su->su_flags) & si->sui_nblocks = le32_to_cpu(su->su_nblocks);
si->sui_flags = le32_to_cpu(su->su_flags) &
~(1UL << NILFS_SEGMENT_USAGE_ACTIVE); ~(1UL << NILFS_SEGMENT_USAGE_ACTIVE);
if (nilfs_segment_is_active(nilfs, segnum + j)) if (nilfs_segment_is_active(nilfs, segnum + j))
si[i + j].sui_flags |= si->sui_flags |=
(1UL << NILFS_SEGMENT_USAGE_ACTIVE); (1UL << NILFS_SEGMENT_USAGE_ACTIVE);
} }
kunmap_atomic(kaddr, KM_USER0); kunmap_atomic(kaddr, KM_USER0);
......
...@@ -43,42 +43,26 @@ void nilfs_sufile_put_segment_usage(struct inode *, __u64, ...@@ -43,42 +43,26 @@ void nilfs_sufile_put_segment_usage(struct inode *, __u64,
struct buffer_head *); struct buffer_head *);
int nilfs_sufile_get_stat(struct inode *, struct nilfs_sustat *); int nilfs_sufile_get_stat(struct inode *, struct nilfs_sustat *);
int nilfs_sufile_get_ncleansegs(struct inode *, unsigned long *); int nilfs_sufile_get_ncleansegs(struct inode *, unsigned long *);
ssize_t nilfs_sufile_get_suinfo(struct inode *, __u64, struct nilfs_suinfo *, ssize_t nilfs_sufile_get_suinfo(struct inode *, __u64, void *, unsigned,
size_t); size_t);
int nilfs_sufile_updatev(struct inode *, __u64 *, size_t, int, size_t *,
void (*dofunc)(struct inode *, __u64,
struct buffer_head *,
struct buffer_head *));
int nilfs_sufile_update(struct inode *, __u64, int, int nilfs_sufile_update(struct inode *, __u64, int,
void (*dofunc)(struct inode *, __u64, void (*dofunc)(struct inode *, __u64,
struct buffer_head *, struct buffer_head *,
struct buffer_head *)); struct buffer_head *));
void nilfs_sufile_do_cancel_free(struct inode *, __u64, struct buffer_head *,
struct buffer_head *);
void nilfs_sufile_do_scrap(struct inode *, __u64, struct buffer_head *, void nilfs_sufile_do_scrap(struct inode *, __u64, struct buffer_head *,
struct buffer_head *); struct buffer_head *);
void nilfs_sufile_do_free(struct inode *, __u64, struct buffer_head *, void nilfs_sufile_do_free(struct inode *, __u64, struct buffer_head *,
struct buffer_head *); struct buffer_head *);
void nilfs_sufile_do_cancel_free(struct inode *, __u64, struct buffer_head *,
struct buffer_head *);
void nilfs_sufile_do_set_error(struct inode *, __u64, struct buffer_head *, void nilfs_sufile_do_set_error(struct inode *, __u64, struct buffer_head *,
struct buffer_head *); struct buffer_head *);
/**
* nilfs_sufile_cancel_free -
* @sufile: inode of segment usage file
* @segnum: segment number
*
* Description:
*
* Return Value: On success, 0 is returned. On error, one of the following
* negative error codes is returned.
*
* %-EIO - I/O error.
*
* %-ENOMEM - Insufficient amount of memory available.
*/
static inline int nilfs_sufile_cancel_free(struct inode *sufile, __u64 segnum)
{
return nilfs_sufile_update(sufile, segnum, 0,
nilfs_sufile_do_cancel_free);
}
/** /**
* nilfs_sufile_scrap - make a segment garbage * nilfs_sufile_scrap - make a segment garbage
* @sufile: inode of segment usage file * @sufile: inode of segment usage file
...@@ -99,6 +83,38 @@ static inline int nilfs_sufile_free(struct inode *sufile, __u64 segnum) ...@@ -99,6 +83,38 @@ static inline int nilfs_sufile_free(struct inode *sufile, __u64 segnum)
return nilfs_sufile_update(sufile, segnum, 0, nilfs_sufile_do_free); return nilfs_sufile_update(sufile, segnum, 0, nilfs_sufile_do_free);
} }
/**
* nilfs_sufile_freev - free segments
* @sufile: inode of segment usage file
* @segnumv: array of segment numbers
* @nsegs: size of @segnumv array
* @ndone: place to store the number of freed segments
*/
static inline int nilfs_sufile_freev(struct inode *sufile, __u64 *segnumv,
size_t nsegs, size_t *ndone)
{
return nilfs_sufile_updatev(sufile, segnumv, nsegs, 0, ndone,
nilfs_sufile_do_free);
}
/**
* nilfs_sufile_cancel_freev - reallocate freeing segments
* @sufile: inode of segment usage file
* @segnumv: array of segment numbers
* @nsegs: size of @segnumv array
* @ndone: place to store the number of cancelled segments
*
* Return Value: On success, 0 is returned. On error, a negative error codes
* is returned.
*/
static inline int nilfs_sufile_cancel_freev(struct inode *sufile,
__u64 *segnumv, size_t nsegs,
size_t *ndone)
{
return nilfs_sufile_updatev(sufile, segnumv, nsegs, 0, ndone,
nilfs_sufile_do_cancel_free);
}
/** /**
* nilfs_sufile_set_error - mark a segment as erroneous * nilfs_sufile_set_error - mark a segment as erroneous
* @sufile: inode of segment usage file * @sufile: inode of segment usage file
......
...@@ -133,7 +133,7 @@ void nilfs_warning(struct super_block *sb, const char *function, ...@@ -133,7 +133,7 @@ void nilfs_warning(struct super_block *sb, const char *function,
static struct kmem_cache *nilfs_inode_cachep; static struct kmem_cache *nilfs_inode_cachep;
struct inode *nilfs_alloc_inode(struct super_block *sb) struct inode *nilfs_alloc_inode_common(struct the_nilfs *nilfs)
{ {
struct nilfs_inode_info *ii; struct nilfs_inode_info *ii;
...@@ -143,10 +143,15 @@ struct inode *nilfs_alloc_inode(struct super_block *sb) ...@@ -143,10 +143,15 @@ struct inode *nilfs_alloc_inode(struct super_block *sb)
ii->i_bh = NULL; ii->i_bh = NULL;
ii->i_state = 0; ii->i_state = 0;
ii->vfs_inode.i_version = 1; ii->vfs_inode.i_version = 1;
nilfs_btnode_cache_init(&ii->i_btnode_cache); nilfs_btnode_cache_init(&ii->i_btnode_cache, nilfs->ns_bdi);
return &ii->vfs_inode; return &ii->vfs_inode;
} }
struct inode *nilfs_alloc_inode(struct super_block *sb)
{
return nilfs_alloc_inode_common(NILFS_SB(sb)->s_nilfs);
}
void nilfs_destroy_inode(struct inode *inode) void nilfs_destroy_inode(struct inode *inode)
{ {
kmem_cache_free(nilfs_inode_cachep, NILFS_I(inode)); kmem_cache_free(nilfs_inode_cachep, NILFS_I(inode));
......
...@@ -32,7 +32,6 @@ ...@@ -32,7 +32,6 @@
#include "cpfile.h" #include "cpfile.h"
#include "sufile.h" #include "sufile.h"
#include "dat.h" #include "dat.h"
#include "seglist.h"
#include "segbuf.h" #include "segbuf.h"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment