Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e902ec99 authored by Jiro SEKIBA's avatar Jiro SEKIBA Committed by Ryusuke Konishi
Browse files

nilfs2: issue discard request after cleaning segments



This adds a function to send discard requests for given array of
segment numbers, and calls the function when garbage collection
succeeded.

Signed-off-by: default avatarJiro SEKIBA <jir@unicus.jp>
Signed-off-by: default avatarRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
parent 724e6d3f
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -74,6 +74,9 @@ norecovery Disable recovery of the filesystem on mount.
			This disables every write access on the device for
			This disables every write access on the device for
			read-only mounts or snapshots.  This option will fail
			read-only mounts or snapshots.  This option will fail
			for r/w mounts on an unclean volume.
			for r/w mounts on an unclean volume.
discard			Issue discard/TRIM commands to the underlying block
			device when blocks are freed.  This is useful for SSD
			devices and sparse/thinly-provisioned LUNs.


NILFS2 usage
NILFS2 usage
============
============
+10 −0
Original line number Original line Diff line number Diff line
@@ -2560,6 +2560,16 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv,
		set_current_state(TASK_INTERRUPTIBLE);
		set_current_state(TASK_INTERRUPTIBLE);
		schedule_timeout(sci->sc_interval);
		schedule_timeout(sci->sc_interval);
	}
	}
	if (nilfs_test_opt(sbi, DISCARD)) {
		int ret = nilfs_discard_segments(nilfs, sci->sc_freesegs,
						 sci->sc_nfreesegs);
		if (ret) {
			printk(KERN_WARNING
			       "NILFS warning: error %d on discard request, "
			       "turning discards off for the device\n", ret);
			nilfs_clear_opt(sbi, DISCARD);
		}
	}


 out_unlock:
 out_unlock:
	sci->sc_freesegs = NULL;
	sci->sc_freesegs = NULL;
+7 −1
Original line number Original line Diff line number Diff line
@@ -481,6 +481,8 @@ static int nilfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
		seq_printf(seq, ",order=strict");
		seq_printf(seq, ",order=strict");
	if (nilfs_test_opt(sbi, NORECOVERY))
	if (nilfs_test_opt(sbi, NORECOVERY))
		seq_printf(seq, ",norecovery");
		seq_printf(seq, ",norecovery");
	if (nilfs_test_opt(sbi, DISCARD))
		seq_printf(seq, ",discard");


	return 0;
	return 0;
}
}
@@ -550,7 +552,7 @@ static const struct export_operations nilfs_export_ops = {
enum {
enum {
	Opt_err_cont, Opt_err_panic, Opt_err_ro,
	Opt_err_cont, Opt_err_panic, Opt_err_ro,
	Opt_nobarrier, Opt_snapshot, Opt_order, Opt_norecovery,
	Opt_nobarrier, Opt_snapshot, Opt_order, Opt_norecovery,
	Opt_err,
	Opt_discard, Opt_err,
};
};


static match_table_t tokens = {
static match_table_t tokens = {
@@ -561,6 +563,7 @@ static match_table_t tokens = {
	{Opt_snapshot, "cp=%u"},
	{Opt_snapshot, "cp=%u"},
	{Opt_order, "order=%s"},
	{Opt_order, "order=%s"},
	{Opt_norecovery, "norecovery"},
	{Opt_norecovery, "norecovery"},
	{Opt_discard, "discard"},
	{Opt_err, NULL}
	{Opt_err, NULL}
};
};


@@ -614,6 +617,9 @@ static int parse_options(char *options, struct super_block *sb)
		case Opt_norecovery:
		case Opt_norecovery:
			nilfs_set_opt(sbi, NORECOVERY);
			nilfs_set_opt(sbi, NORECOVERY);
			break;
			break;
		case Opt_discard:
			nilfs_set_opt(sbi, DISCARD);
			break;
		default:
		default:
			printk(KERN_ERR
			printk(KERN_ERR
			       "NILFS: Unrecognized mount option \"%s\"\n", p);
			       "NILFS: Unrecognized mount option \"%s\"\n", p);
+38 −0
Original line number Original line Diff line number Diff line
@@ -646,6 +646,44 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
	goto out;
	goto out;
}
}


int nilfs_discard_segments(struct the_nilfs *nilfs, __u64 *segnump,
			    size_t nsegs)
{
	sector_t seg_start, seg_end;
	sector_t start = 0, nblocks = 0;
	unsigned int sects_per_block;
	__u64 *sn;
	int ret = 0;

	sects_per_block = (1 << nilfs->ns_blocksize_bits) /
		bdev_logical_block_size(nilfs->ns_bdev);
	for (sn = segnump; sn < segnump + nsegs; sn++) {
		nilfs_get_segment_range(nilfs, *sn, &seg_start, &seg_end);

		if (!nblocks) {
			start = seg_start;
			nblocks = seg_end - seg_start + 1;
		} else if (start + nblocks == seg_start) {
			nblocks += seg_end - seg_start + 1;
		} else {
			ret = blkdev_issue_discard(nilfs->ns_bdev,
						   start * sects_per_block,
						   nblocks * sects_per_block,
						   GFP_NOFS,
						   DISCARD_FL_BARRIER);
			if (ret < 0)
				return ret;
			nblocks = 0;
		}
	}
	if (nblocks)
		ret = blkdev_issue_discard(nilfs->ns_bdev,
					   start * sects_per_block,
					   nblocks * sects_per_block,
					   GFP_NOFS, DISCARD_FL_BARRIER);
	return ret;
}

int nilfs_count_free_blocks(struct the_nilfs *nilfs, sector_t *nblocks)
int nilfs_count_free_blocks(struct the_nilfs *nilfs, sector_t *nblocks)
{
{
	struct inode *dat = nilfs_dat_inode(nilfs);
	struct inode *dat = nilfs_dat_inode(nilfs);
+1 −0
Original line number Original line Diff line number Diff line
@@ -221,6 +221,7 @@ struct the_nilfs *find_or_create_nilfs(struct block_device *);
void put_nilfs(struct the_nilfs *);
void put_nilfs(struct the_nilfs *);
int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *);
int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *);
int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *);
int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *);
int nilfs_discard_segments(struct the_nilfs *, __u64 *, size_t);
int nilfs_count_free_blocks(struct the_nilfs *, sector_t *);
int nilfs_count_free_blocks(struct the_nilfs *, sector_t *);
struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *, int, __u64);
struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *, int, __u64);
int nilfs_checkpoint_is_mounted(struct the_nilfs *, __u64, int);
int nilfs_checkpoint_is_mounted(struct the_nilfs *, __u64, int);
Loading