diff options
author | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2015-04-16 15:46:42 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-17 09:04:04 -0400 |
commit | 53a2c3bdf4132c2c9cc3581e15265fd962f34fa8 (patch) | |
tree | ef5c9ff41dd9adbc5dd1fcf6895159b9e559429c | |
parent | fa33915c92b43f5a4e95649f81303cc089b10dc6 (diff) |
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>
-rw-r--r-- | fs/nilfs2/cpfile.c | 58 |
1 files changed, 52 insertions, 6 deletions
diff --git a/fs/nilfs2/cpfile.c b/fs/nilfs2/cpfile.c index 0d58075f34e2..b6596cab9e99 100644 --- a/fs/nilfs2/cpfile.c +++ b/fs/nilfs2/cpfile.c | |||
@@ -53,6 +53,13 @@ nilfs_cpfile_get_offset(const struct inode *cpfile, __u64 cno) | |||
53 | return do_div(tcno, nilfs_cpfile_checkpoints_per_block(cpfile)); | 53 | return do_div(tcno, nilfs_cpfile_checkpoints_per_block(cpfile)); |
54 | } | 54 | } |
55 | 55 | ||
56 | static __u64 nilfs_cpfile_first_checkpoint_in_block(const struct inode *cpfile, | ||
57 | unsigned long blkoff) | ||
58 | { | ||
59 | return (__u64)nilfs_cpfile_checkpoints_per_block(cpfile) * blkoff | ||
60 | + 1 - NILFS_MDT(cpfile)->mi_first_entry_offset; | ||
61 | } | ||
62 | |||
56 | static unsigned long | 63 | static unsigned long |
57 | nilfs_cpfile_checkpoints_in_block(const struct inode *cpfile, | 64 | nilfs_cpfile_checkpoints_in_block(const struct inode *cpfile, |
58 | __u64 curr, | 65 | __u64 curr, |
@@ -146,6 +153,44 @@ static inline int nilfs_cpfile_get_checkpoint_block(struct inode *cpfile, | |||
146 | create, nilfs_cpfile_block_init, bhp); | 153 | create, nilfs_cpfile_block_init, bhp); |
147 | } | 154 | } |
148 | 155 | ||
156 | /** | ||
157 | * nilfs_cpfile_find_checkpoint_block - find and get a buffer on cpfile | ||
158 | * @cpfile: inode of cpfile | ||
159 | * @start_cno: start checkpoint number (inclusive) | ||
160 | * @end_cno: end checkpoint number (inclusive) | ||
161 | * @cnop: place to store the next checkpoint number | ||
162 | * @bhp: place to store a pointer to buffer_head struct | ||
163 | * | ||
164 | * Return Value: On success, it returns 0. On error, the following negative | ||
165 | * error code is returned. | ||
166 | * | ||
167 | * %-ENOMEM - Insufficient memory available. | ||
168 | * | ||
169 | * %-EIO - I/O error | ||
170 | * | ||
171 | * %-ENOENT - no block exists in the range. | ||
172 | */ | ||
173 | static int nilfs_cpfile_find_checkpoint_block(struct inode *cpfile, | ||
174 | __u64 start_cno, __u64 end_cno, | ||
175 | __u64 *cnop, | ||
176 | struct buffer_head **bhp) | ||
177 | { | ||
178 | unsigned long start, end, blkoff; | ||
179 | int ret; | ||
180 | |||
181 | if (unlikely(start_cno > end_cno)) | ||
182 | return -ENOENT; | ||
183 | |||
184 | start = nilfs_cpfile_get_blkoff(cpfile, start_cno); | ||
185 | end = nilfs_cpfile_get_blkoff(cpfile, end_cno); | ||
186 | |||
187 | ret = nilfs_mdt_find_block(cpfile, start, end, &blkoff, bhp); | ||
188 | if (!ret) | ||
189 | *cnop = (blkoff == start) ? start_cno : | ||
190 | nilfs_cpfile_first_checkpoint_in_block(cpfile, blkoff); | ||
191 | return ret; | ||
192 | } | ||
193 | |||
149 | static inline int nilfs_cpfile_delete_checkpoint_block(struct inode *cpfile, | 194 | static inline int nilfs_cpfile_delete_checkpoint_block(struct inode *cpfile, |
150 | __u64 cno) | 195 | __u64 cno) |
151 | { | 196 | { |
@@ -403,14 +448,15 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop, | |||
403 | return -ENOENT; /* checkpoint number 0 is invalid */ | 448 | return -ENOENT; /* checkpoint number 0 is invalid */ |
404 | down_read(&NILFS_MDT(cpfile)->mi_sem); | 449 | down_read(&NILFS_MDT(cpfile)->mi_sem); |
405 | 450 | ||
406 | for (n = 0; cno < cur_cno && n < nci; cno += ncps) { | 451 | for (n = 0; n < nci; cno += ncps) { |
407 | ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, cur_cno); | 452 | ret = nilfs_cpfile_find_checkpoint_block( |
408 | ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &bh); | 453 | cpfile, cno, cur_cno - 1, &cno, &bh); |
409 | if (ret < 0) { | 454 | if (ret < 0) { |
410 | if (ret != -ENOENT) | 455 | if (likely(ret == -ENOENT)) |
411 | goto out; | 456 | break; |
412 | continue; /* skip hole */ | 457 | goto out; |
413 | } | 458 | } |
459 | ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, cur_cno); | ||
414 | 460 | ||
415 | kaddr = kmap_atomic(bh->b_page); | 461 | kaddr = kmap_atomic(bh->b_page); |
416 | cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr); | 462 | cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr); |