aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nilfs2
diff options
context:
space:
mode:
authorRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2011-05-04 12:23:57 -0400
committerRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2011-05-10 09:21:45 -0400
commit619205da5b567504310daf829dede1187fa29bbc (patch)
treecd672bb647ff22c711d93437fc53821852f27eba /fs/nilfs2
parent56eb55388580ebd51f3bbd9af40ebb56849356af (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.c34
-rw-r--r--fs/nilfs2/sufile.c73
-rw-r--r--fs/nilfs2/sufile.h1
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
701static 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);
729out:
730 return ret;
731}
732
701static int nilfs_ioctl_get_info(struct inode *inode, struct file *filp, 733static 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
34struct nilfs_sufile_info { 34struct 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
39static inline struct nilfs_sufile_info *NILFS_SUI(struct inode *sufile) 41static 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 */
263int 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
37unsigned long nilfs_sufile_get_ncleansegs(struct inode *sufile); 37unsigned long nilfs_sufile_get_ncleansegs(struct inode *sufile);
38 38
39int nilfs_sufile_set_alloc_range(struct inode *sufile, __u64 start, __u64 end);
39int nilfs_sufile_alloc(struct inode *, __u64 *); 40int nilfs_sufile_alloc(struct inode *, __u64 *);
40int nilfs_sufile_mark_dirty(struct inode *sufile, __u64 segnum); 41int nilfs_sufile_mark_dirty(struct inode *sufile, __u64 segnum);
41int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum, 42int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum,