diff options
author | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2011-05-04 12:23:57 -0400 |
---|---|---|
committer | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2011-05-10 09:21:45 -0400 |
commit | 619205da5b567504310daf829dede1187fa29bbc (patch) | |
tree | cd672bb647ff22c711d93437fc53821852f27eba /fs/nilfs2 | |
parent | 56eb55388580ebd51f3bbd9af40ebb56849356af (diff) |
nilfs2: add ioctl which limits range of segment to be allocated
This adds a new ioctl command which limits range of segment to be
allocated. This is intended to gather data whithin a range of the
partition before shrinking the filesystem, or to control new log
location for some purpose.
If a range is specified by the ioctl, segment allocator of nilfs tries
to allocate new segments from the range unless no free segments are
available there.
Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Diffstat (limited to 'fs/nilfs2')
-rw-r--r-- | fs/nilfs2/ioctl.c | 34 | ||||
-rw-r--r-- | fs/nilfs2/sufile.c | 73 | ||||
-rw-r--r-- | fs/nilfs2/sufile.h | 1 |
3 files changed, 98 insertions, 10 deletions
diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index f2469ba6246b..6f617773a7f7 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c | |||
@@ -698,6 +698,38 @@ static int nilfs_ioctl_sync(struct inode *inode, struct file *filp, | |||
698 | return 0; | 698 | return 0; |
699 | } | 699 | } |
700 | 700 | ||
701 | static int nilfs_ioctl_set_alloc_range(struct inode *inode, void __user *argp) | ||
702 | { | ||
703 | struct the_nilfs *nilfs = inode->i_sb->s_fs_info; | ||
704 | __u64 range[2]; | ||
705 | __u64 minseg, maxseg; | ||
706 | unsigned long segbytes; | ||
707 | int ret = -EPERM; | ||
708 | |||
709 | if (!capable(CAP_SYS_ADMIN)) | ||
710 | goto out; | ||
711 | |||
712 | ret = -EFAULT; | ||
713 | if (copy_from_user(range, argp, sizeof(__u64[2]))) | ||
714 | goto out; | ||
715 | |||
716 | ret = -ERANGE; | ||
717 | if (range[1] > i_size_read(inode->i_sb->s_bdev->bd_inode)) | ||
718 | goto out; | ||
719 | |||
720 | segbytes = nilfs->ns_blocks_per_segment * nilfs->ns_blocksize; | ||
721 | |||
722 | minseg = range[0] + segbytes - 1; | ||
723 | do_div(minseg, segbytes); | ||
724 | maxseg = NILFS_SB2_OFFSET_BYTES(range[1]); | ||
725 | do_div(maxseg, segbytes); | ||
726 | maxseg--; | ||
727 | |||
728 | ret = nilfs_sufile_set_alloc_range(nilfs->ns_sufile, minseg, maxseg); | ||
729 | out: | ||
730 | return ret; | ||
731 | } | ||
732 | |||
701 | static int nilfs_ioctl_get_info(struct inode *inode, struct file *filp, | 733 | static int nilfs_ioctl_get_info(struct inode *inode, struct file *filp, |
702 | unsigned int cmd, void __user *argp, | 734 | unsigned int cmd, void __user *argp, |
703 | size_t membsz, | 735 | size_t membsz, |
@@ -763,6 +795,8 @@ long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
763 | return nilfs_ioctl_clean_segments(inode, filp, cmd, argp); | 795 | return nilfs_ioctl_clean_segments(inode, filp, cmd, argp); |
764 | case NILFS_IOCTL_SYNC: | 796 | case NILFS_IOCTL_SYNC: |
765 | return nilfs_ioctl_sync(inode, filp, cmd, argp); | 797 | return nilfs_ioctl_sync(inode, filp, cmd, argp); |
798 | case NILFS_IOCTL_SET_ALLOC_RANGE: | ||
799 | return nilfs_ioctl_set_alloc_range(inode, argp); | ||
766 | default: | 800 | default: |
767 | return -ENOTTY; | 801 | return -ENOTTY; |
768 | } | 802 | } |
diff --git a/fs/nilfs2/sufile.c b/fs/nilfs2/sufile.c index 1d6f488ccae8..f4374df00ad5 100644 --- a/fs/nilfs2/sufile.c +++ b/fs/nilfs2/sufile.c | |||
@@ -33,7 +33,9 @@ | |||
33 | 33 | ||
34 | struct nilfs_sufile_info { | 34 | struct nilfs_sufile_info { |
35 | struct nilfs_mdt_info mi; | 35 | struct nilfs_mdt_info mi; |
36 | unsigned long ncleansegs; | 36 | unsigned long ncleansegs;/* number of clean segments */ |
37 | __u64 allocmin; /* lower limit of allocatable segment range */ | ||
38 | __u64 allocmax; /* upper limit of allocatable segment range */ | ||
37 | }; | 39 | }; |
38 | 40 | ||
39 | static inline struct nilfs_sufile_info *NILFS_SUI(struct inode *sufile) | 41 | static inline struct nilfs_sufile_info *NILFS_SUI(struct inode *sufile) |
@@ -248,6 +250,35 @@ int nilfs_sufile_update(struct inode *sufile, __u64 segnum, int create, | |||
248 | } | 250 | } |
249 | 251 | ||
250 | /** | 252 | /** |
253 | * nilfs_sufile_set_alloc_range - limit range of segment to be allocated | ||
254 | * @sufile: inode of segment usage file | ||
255 | * @start: minimum segment number of allocatable region (inclusive) | ||
256 | * @end: maximum segment number of allocatable region (inclusive) | ||
257 | * | ||
258 | * Return Value: On success, 0 is returned. On error, one of the | ||
259 | * following negative error codes is returned. | ||
260 | * | ||
261 | * %-ERANGE - invalid segment region | ||
262 | */ | ||
263 | int nilfs_sufile_set_alloc_range(struct inode *sufile, __u64 start, __u64 end) | ||
264 | { | ||
265 | struct nilfs_sufile_info *sui = NILFS_SUI(sufile); | ||
266 | __u64 nsegs; | ||
267 | int ret = -ERANGE; | ||
268 | |||
269 | down_write(&NILFS_MDT(sufile)->mi_sem); | ||
270 | nsegs = nilfs_sufile_get_nsegments(sufile); | ||
271 | |||
272 | if (start <= end && end < nsegs) { | ||
273 | sui->allocmin = start; | ||
274 | sui->allocmax = end; | ||
275 | ret = 0; | ||
276 | } | ||
277 | up_write(&NILFS_MDT(sufile)->mi_sem); | ||
278 | return ret; | ||
279 | } | ||
280 | |||
281 | /** | ||
251 | * nilfs_sufile_alloc - allocate a segment | 282 | * nilfs_sufile_alloc - allocate a segment |
252 | * @sufile: inode of segment usage file | 283 | * @sufile: inode of segment usage file |
253 | * @segnump: pointer to segment number | 284 | * @segnump: pointer to segment number |
@@ -269,11 +300,12 @@ int nilfs_sufile_alloc(struct inode *sufile, __u64 *segnump) | |||
269 | struct buffer_head *header_bh, *su_bh; | 300 | struct buffer_head *header_bh, *su_bh; |
270 | struct nilfs_sufile_header *header; | 301 | struct nilfs_sufile_header *header; |
271 | struct nilfs_segment_usage *su; | 302 | struct nilfs_segment_usage *su; |
303 | struct nilfs_sufile_info *sui = NILFS_SUI(sufile); | ||
272 | size_t susz = NILFS_MDT(sufile)->mi_entry_size; | 304 | size_t susz = NILFS_MDT(sufile)->mi_entry_size; |
273 | __u64 segnum, maxsegnum, last_alloc; | 305 | __u64 segnum, maxsegnum, last_alloc; |
274 | void *kaddr; | 306 | void *kaddr; |
275 | unsigned long nsegments, ncleansegs, nsus; | 307 | unsigned long nsegments, ncleansegs, nsus, cnt; |
276 | int ret, i, j; | 308 | int ret, j; |
277 | 309 | ||
278 | down_write(&NILFS_MDT(sufile)->mi_sem); | 310 | down_write(&NILFS_MDT(sufile)->mi_sem); |
279 | 311 | ||
@@ -287,13 +319,31 @@ int nilfs_sufile_alloc(struct inode *sufile, __u64 *segnump) | |||
287 | kunmap_atomic(kaddr, KM_USER0); | 319 | kunmap_atomic(kaddr, KM_USER0); |
288 | 320 | ||
289 | nsegments = nilfs_sufile_get_nsegments(sufile); | 321 | nsegments = nilfs_sufile_get_nsegments(sufile); |
322 | maxsegnum = sui->allocmax; | ||
290 | segnum = last_alloc + 1; | 323 | segnum = last_alloc + 1; |
291 | maxsegnum = nsegments - 1; | 324 | if (segnum < sui->allocmin || segnum > sui->allocmax) |
292 | for (i = 0; i < nsegments; i += nsus) { | 325 | segnum = sui->allocmin; |
293 | if (segnum >= nsegments) { | 326 | |
294 | /* wrap around */ | 327 | for (cnt = 0; cnt < nsegments; cnt += nsus) { |
295 | segnum = 0; | 328 | if (segnum > maxsegnum) { |
296 | maxsegnum = last_alloc; | 329 | if (cnt < sui->allocmax - sui->allocmin + 1) { |
330 | /* | ||
331 | * wrap around in the limited region. | ||
332 | * if allocation started from | ||
333 | * sui->allocmin, this never happens. | ||
334 | */ | ||
335 | segnum = sui->allocmin; | ||
336 | maxsegnum = last_alloc; | ||
337 | } else if (segnum > sui->allocmin && | ||
338 | sui->allocmax + 1 < nsegments) { | ||
339 | segnum = sui->allocmax + 1; | ||
340 | maxsegnum = nsegments - 1; | ||
341 | } else if (sui->allocmin > 0) { | ||
342 | segnum = 0; | ||
343 | maxsegnum = sui->allocmin - 1; | ||
344 | } else { | ||
345 | break; /* never happens */ | ||
346 | } | ||
297 | } | 347 | } |
298 | ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 1, | 348 | ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 1, |
299 | &su_bh); | 349 | &su_bh); |
@@ -319,7 +369,7 @@ int nilfs_sufile_alloc(struct inode *sufile, __u64 *segnump) | |||
319 | header->sh_last_alloc = cpu_to_le64(segnum); | 369 | header->sh_last_alloc = cpu_to_le64(segnum); |
320 | kunmap_atomic(kaddr, KM_USER0); | 370 | kunmap_atomic(kaddr, KM_USER0); |
321 | 371 | ||
322 | NILFS_SUI(sufile)->ncleansegs--; | 372 | sui->ncleansegs--; |
323 | nilfs_mdt_mark_buffer_dirty(header_bh); | 373 | nilfs_mdt_mark_buffer_dirty(header_bh); |
324 | nilfs_mdt_mark_buffer_dirty(su_bh); | 374 | nilfs_mdt_mark_buffer_dirty(su_bh); |
325 | nilfs_mdt_mark_dirty(sufile); | 375 | nilfs_mdt_mark_dirty(sufile); |
@@ -679,6 +729,9 @@ int nilfs_sufile_read(struct super_block *sb, size_t susize, | |||
679 | kunmap_atomic(kaddr, KM_USER0); | 729 | kunmap_atomic(kaddr, KM_USER0); |
680 | brelse(header_bh); | 730 | brelse(header_bh); |
681 | 731 | ||
732 | sui->allocmax = nilfs_sufile_get_nsegments(sufile) - 1; | ||
733 | sui->allocmin = 0; | ||
734 | |||
682 | unlock_new_inode(sufile); | 735 | unlock_new_inode(sufile); |
683 | out: | 736 | out: |
684 | *inodep = sufile; | 737 | *inodep = sufile; |
diff --git a/fs/nilfs2/sufile.h b/fs/nilfs2/sufile.h index a943fbacb45b..57bfee9cd02d 100644 --- a/fs/nilfs2/sufile.h +++ b/fs/nilfs2/sufile.h | |||
@@ -36,6 +36,7 @@ static inline unsigned long nilfs_sufile_get_nsegments(struct inode *sufile) | |||
36 | 36 | ||
37 | unsigned long nilfs_sufile_get_ncleansegs(struct inode *sufile); | 37 | unsigned long nilfs_sufile_get_ncleansegs(struct inode *sufile); |
38 | 38 | ||
39 | int nilfs_sufile_set_alloc_range(struct inode *sufile, __u64 start, __u64 end); | ||
39 | int nilfs_sufile_alloc(struct inode *, __u64 *); | 40 | int nilfs_sufile_alloc(struct inode *, __u64 *); |
40 | int nilfs_sufile_mark_dirty(struct inode *sufile, __u64 segnum); | 41 | int nilfs_sufile_mark_dirty(struct inode *sufile, __u64 segnum); |
41 | int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum, | 42 | int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum, |