Commit 619205da5b567504310daf829dede1187fa29bbc

Authored by Ryusuke Konishi
1 parent 56eb553885

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>

Showing 4 changed files with 100 additions and 10 deletions Side-by-side Diff

... ... @@ -698,6 +698,38 @@
698 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 733 static int nilfs_ioctl_get_info(struct inode *inode, struct file *filp,
702 734 unsigned int cmd, void __user *argp,
703 735 size_t membsz,
... ... @@ -763,6 +795,8 @@
763 795 return nilfs_ioctl_clean_segments(inode, filp, cmd, argp);
764 796 case NILFS_IOCTL_SYNC:
765 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 800 default:
767 801 return -ENOTTY;
768 802 }
... ... @@ -33,7 +33,9 @@
33 33  
34 34 struct nilfs_sufile_info {
35 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 41 static inline struct nilfs_sufile_info *NILFS_SUI(struct inode *sufile)
... ... @@ -248,6 +250,35 @@
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 282 * nilfs_sufile_alloc - allocate a segment
252 283 * @sufile: inode of segment usage file
253 284 * @segnump: pointer to segment number
254 285  
... ... @@ -269,11 +300,12 @@
269 300 struct buffer_head *header_bh, *su_bh;
270 301 struct nilfs_sufile_header *header;
271 302 struct nilfs_segment_usage *su;
  303 + struct nilfs_sufile_info *sui = NILFS_SUI(sufile);
272 304 size_t susz = NILFS_MDT(sufile)->mi_entry_size;
273 305 __u64 segnum, maxsegnum, last_alloc;
274 306 void *kaddr;
275   - unsigned long nsegments, ncleansegs, nsus;
276   - int ret, i, j;
  307 + unsigned long nsegments, ncleansegs, nsus, cnt;
  308 + int ret, j;
277 309  
278 310 down_write(&NILFS_MDT(sufile)->mi_sem);
279 311  
280 312  
... ... @@ -287,13 +319,31 @@
287 319 kunmap_atomic(kaddr, KM_USER0);
288 320  
289 321 nsegments = nilfs_sufile_get_nsegments(sufile);
  322 + maxsegnum = sui->allocmax;
290 323 segnum = last_alloc + 1;
291   - maxsegnum = nsegments - 1;
292   - for (i = 0; i < nsegments; i += nsus) {
293   - if (segnum >= nsegments) {
294   - /* wrap around */
295   - segnum = 0;
296   - maxsegnum = last_alloc;
  324 + if (segnum < sui->allocmin || segnum > sui->allocmax)
  325 + segnum = sui->allocmin;
  326 +
  327 + for (cnt = 0; cnt < nsegments; cnt += nsus) {
  328 + if (segnum > maxsegnum) {
  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 348 ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 1,
299 349 &su_bh);
... ... @@ -319,7 +369,7 @@
319 369 header->sh_last_alloc = cpu_to_le64(segnum);
320 370 kunmap_atomic(kaddr, KM_USER0);
321 371  
322   - NILFS_SUI(sufile)->ncleansegs--;
  372 + sui->ncleansegs--;
323 373 nilfs_mdt_mark_buffer_dirty(header_bh);
324 374 nilfs_mdt_mark_buffer_dirty(su_bh);
325 375 nilfs_mdt_mark_dirty(sufile);
... ... @@ -678,6 +728,9 @@
678 728 sui->ncleansegs = le64_to_cpu(header->sh_ncleansegs);
679 729 kunmap_atomic(kaddr, KM_USER0);
680 730 brelse(header_bh);
  731 +
  732 + sui->allocmax = nilfs_sufile_get_nsegments(sufile) - 1;
  733 + sui->allocmin = 0;
681 734  
682 735 unlock_new_inode(sufile);
683 736 out:
... ... @@ -36,6 +36,7 @@
36 36  
37 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 40 int nilfs_sufile_alloc(struct inode *, __u64 *);
40 41 int nilfs_sufile_mark_dirty(struct inode *sufile, __u64 segnum);
41 42 int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum,
include/linux/nilfs2_fs.h
... ... @@ -845,6 +845,8 @@
845 845 _IOR(NILFS_IOCTL_IDENT, 0x8A, __u64)
846 846 #define NILFS_IOCTL_RESIZE \
847 847 _IOW(NILFS_IOCTL_IDENT, 0x8B, __u64)
  848 +#define NILFS_IOCTL_SET_ALLOC_RANGE \
  849 + _IOW(NILFS_IOCTL_IDENT, 0x8C, __u64[2])
848 850  
849 851 #endif /* _LINUX_NILFS_FS_H */