forked from Minki/linux
nilfs2: improve execution time of NILFS_IOCTL_GET_CPINFO ioctl
The older a filesystem gets, the slower lscp command becomes. This is because nilfs_cpfile_do_get_cpinfo() function meets more hole blocks as the start offset of valid checkpoint numbers gets bigger. This reduces the overhead by skipping hole blocks efficiently with nilfs_mdt_find_block() helper. A measurement result of this patch is as follows: Before: $ time lscp CNO DATE TIME MODE FLG BLKCNT ICNT 5769303 2015-02-22 19:31:33 cp - 108 1 5769304 2015-02-22 19:38:54 cp - 108 1 real 0m0.182s user 0m0.003s sys 0m0.180s After: $ time lscp CNO DATE TIME MODE FLG BLKCNT ICNT 5769303 2015-02-22 19:31:33 cp - 108 1 5769304 2015-02-22 19:38:54 cp - 108 1 real 0m0.003s user 0m0.001s sys 0m0.002s Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
fa33915c92
commit
53a2c3bdf4
@ -53,6 +53,13 @@ nilfs_cpfile_get_offset(const struct inode *cpfile, __u64 cno)
|
|||||||
return do_div(tcno, nilfs_cpfile_checkpoints_per_block(cpfile));
|
return do_div(tcno, nilfs_cpfile_checkpoints_per_block(cpfile));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static __u64 nilfs_cpfile_first_checkpoint_in_block(const struct inode *cpfile,
|
||||||
|
unsigned long blkoff)
|
||||||
|
{
|
||||||
|
return (__u64)nilfs_cpfile_checkpoints_per_block(cpfile) * blkoff
|
||||||
|
+ 1 - NILFS_MDT(cpfile)->mi_first_entry_offset;
|
||||||
|
}
|
||||||
|
|
||||||
static unsigned long
|
static unsigned long
|
||||||
nilfs_cpfile_checkpoints_in_block(const struct inode *cpfile,
|
nilfs_cpfile_checkpoints_in_block(const struct inode *cpfile,
|
||||||
__u64 curr,
|
__u64 curr,
|
||||||
@ -146,6 +153,44 @@ static inline int nilfs_cpfile_get_checkpoint_block(struct inode *cpfile,
|
|||||||
create, nilfs_cpfile_block_init, bhp);
|
create, nilfs_cpfile_block_init, bhp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nilfs_cpfile_find_checkpoint_block - find and get a buffer on cpfile
|
||||||
|
* @cpfile: inode of cpfile
|
||||||
|
* @start_cno: start checkpoint number (inclusive)
|
||||||
|
* @end_cno: end checkpoint number (inclusive)
|
||||||
|
* @cnop: place to store the next checkpoint number
|
||||||
|
* @bhp: place to store a pointer to buffer_head struct
|
||||||
|
*
|
||||||
|
* Return Value: On success, it returns 0. On error, the following negative
|
||||||
|
* error code is returned.
|
||||||
|
*
|
||||||
|
* %-ENOMEM - Insufficient memory available.
|
||||||
|
*
|
||||||
|
* %-EIO - I/O error
|
||||||
|
*
|
||||||
|
* %-ENOENT - no block exists in the range.
|
||||||
|
*/
|
||||||
|
static int nilfs_cpfile_find_checkpoint_block(struct inode *cpfile,
|
||||||
|
__u64 start_cno, __u64 end_cno,
|
||||||
|
__u64 *cnop,
|
||||||
|
struct buffer_head **bhp)
|
||||||
|
{
|
||||||
|
unsigned long start, end, blkoff;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (unlikely(start_cno > end_cno))
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
start = nilfs_cpfile_get_blkoff(cpfile, start_cno);
|
||||||
|
end = nilfs_cpfile_get_blkoff(cpfile, end_cno);
|
||||||
|
|
||||||
|
ret = nilfs_mdt_find_block(cpfile, start, end, &blkoff, bhp);
|
||||||
|
if (!ret)
|
||||||
|
*cnop = (blkoff == start) ? start_cno :
|
||||||
|
nilfs_cpfile_first_checkpoint_in_block(cpfile, blkoff);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int nilfs_cpfile_delete_checkpoint_block(struct inode *cpfile,
|
static inline int nilfs_cpfile_delete_checkpoint_block(struct inode *cpfile,
|
||||||
__u64 cno)
|
__u64 cno)
|
||||||
{
|
{
|
||||||
@ -403,14 +448,15 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop,
|
|||||||
return -ENOENT; /* checkpoint number 0 is invalid */
|
return -ENOENT; /* checkpoint number 0 is invalid */
|
||||||
down_read(&NILFS_MDT(cpfile)->mi_sem);
|
down_read(&NILFS_MDT(cpfile)->mi_sem);
|
||||||
|
|
||||||
for (n = 0; cno < cur_cno && n < nci; cno += ncps) {
|
for (n = 0; n < nci; cno += ncps) {
|
||||||
ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, cur_cno);
|
ret = nilfs_cpfile_find_checkpoint_block(
|
||||||
ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &bh);
|
cpfile, cno, cur_cno - 1, &cno, &bh);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (ret != -ENOENT)
|
if (likely(ret == -ENOENT))
|
||||||
goto out;
|
break;
|
||||||
continue; /* skip hole */
|
goto out;
|
||||||
}
|
}
|
||||||
|
ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, cur_cno);
|
||||||
|
|
||||||
kaddr = kmap_atomic(bh->b_page);
|
kaddr = kmap_atomic(bh->b_page);
|
||||||
cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr);
|
cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr);
|
||||||
|
Loading…
Reference in New Issue
Block a user